Controlling 32 or more stepper motors

No, that's not the case. I need to be able to turn them in both directions. I won't need their current positions while commanding them to move, i.e., my commands will simply be like move x steps clockwise and move y steps counter-clockwise.

Don't use delay(). Use non-blocking if (time-calculation) in void loop() to allow more than one thing happening "at the same time", aka millis-code taught here.

delay(1) wastes 16000 cpu cycles that "millis code" uses.

No that is not how things work. There is no requirement to generate PWM. I think you might be mixing up PWM with clock pulses, two totally different things.

Not the impression I got, in which case you have an even bigger problem on your hands.

First off you do need to account for backlash and also you do need to track both the direction an position of each motor. So that you know when to change direction.

However even worse you will need some sort of reference for each motor. That is normally done by having the motor's position trigger a switch, optical or mechanical so it can start up in the same position each time.
You just made your project a lot lot harder, and it wasn't easy to begin with.

1 Like

Just to make things clear... The code I wrote is targeted at kinetic art, where the motors turn between two limits, like the BMW display. So not for endless continuous rotation.
Zero is (could be) the starting point. The user enters a number of steps from there (+ or -). The motor tries to get there at max speed, with some basic acceleration/deceleration and/or optional basic speed reduction.
All motors take a single step every ~2ms. Full motor code is in a single goPos() function.
Each TPIC power shift register drives two motors, so 16 chips are needed for 32 motors.
The daisy-chain of TPIC chips is controlled with 3 or 4 pins of the Arduino (SPI).
@ba47 has added hardware/code to save all motor positions to the built-in EEPROM of the Arduino on power-off or in case of a power-cut.
Leo..

1 Like

I remember that video. Impressive.

https://forum.arduino.cc/t/creating-the-bmw-kinetic-sculpture/670206/275?u=davex

Got it. The width of the pulse does not matter. The pulses energize the coils.

I am aware of this start up issue, and for now I have deferred it. In my use case, the positions for each motor are well-defined, finite and in cyclic patterns. For example, let's say at time t0 stepper A is at some position which we call "home position". At time t1 it moves +10 steps, at t2 it moves -14 steps (negative means reverse direction), at t3 it moves -10 steps, and so on ... and at the last step t100 it moves +15 steps which would bring it back to the home position (i.e., same as t0). After that when the user gives an external command (maybe a simple switch), the movement starts again from t1 to t100.

By deferring the start up issue, the major thing I am giving away is handling power-cuts. After a power-cut, the steppers might not be at home positions; for now I am thinking of manually adjusting everything whenever that happens simply because it's my first prototype. For future, I have some simple ideas like tracking the progress of my entire system (e.g., time step + some more info) using a separate stepper motor T, and at startup reading T's position to infer where all my other stepper motors currently are. Or simply track using EEPROM (although it limits the lifetime).

Thanks or the summary @Wawa. This makes a lot of sense. I am looking at the switch (nowPos[i] & 3) code block which is packing the bits in val[*], which are then packed in chain using shift operators and sent out using SPI.transfer16(chain);. This is neat. I have two questions here:

  1. How did you come up with the amount of delay between pulses? I see the following in goPos():

How did you compute the required delay should be 2440? In comparison, let's say we have the following code:

chain = ... ; // some combination of 0s and 1s
SPI.transfer16(chain);
digitalWrite(latchPin, HIGH);
digitalWrite(latchPin, LOW);
chain = ... ; // some other combination of 0s and 1s
SPI.transfer16(chain);
digitalWrite(latchPin, HIGH);
digitalWrite(latchPin, LOW);
chain = ... ; // some other combination of 0s and 1s
SPI.transfer16(chain);
digitalWrite(latchPin, HIGH);
digitalWrite(latchPin, LOW);

Notice this code has no delays between SPI.transfer16() calls. What will happen to the stepper in this case? Will it miss the second pulse because it went by too fast maybe?

  1. Is there an easy way to understand the 4-bit combinations that you're storing in val inside the switch block? I can see the 4 bits will correspond to the 4 stepper wires Or,Ye,Pi,Bl and (if I am not wrong) I believe one can construct a truth table to find out when the stepper will move 1 step clockwise or 1 step counter-clockwise. But I am concerned because the bit combinations seem to differ based on torque (e.g., in your code val[i & 3] = B00000011 for torque but it is B00000001 for "low power"). So, how do I get the entire truth table and how do I pick the two moves (1 step clockwise or 1 step counter-clockwise) from those 16 combinations?

On a related note, I am curious about the wiring of multiple TPIC6B595. I haven't read much on this yet, but looking at the data sheet it seems I can connect them in series by connecting pin 17 (drain7) of first chip to pin 3 (SER IN) of the second. And also connecting pin 13 (SRCK), pin 8 (SRCLR_bar), pin 12 (RCK) with each other. What about pin 18 (SER OUT), pin 9 (G_bar), and the three ground pins (10, 11, 19)?

More importantly, do we need any external diodes/capacitors/resistors/etc. between TPIC6B595 and 28BYJ-48, or between TPIC6B595 and Arduino, or between two TPIC6B595 chips?

You need a 0.1uF ceramic capacitor between the power and ground of every TPIC6B595 chip. The leads must be as short as possible to be effective.

This is called power supply decoupling, without it the chips do not work correctly, especially when you have a lot of chips.

1 Like

12RPM = 12 * 2048 steps/min, / 60 = 409 steps/sec.
Time between steps = 1 / 409 = ...

That delay is not a hard number. It just sets max motor RPM.
I could get 15RPM, by reducing that to 1953us, but cold motors started missing steps.

From memory, stepping 48 motors took about 750us, so I had about 1500us in between steps to do other things.

Step sequence is just a BCD table, and I simply extracted that from the motor position value with bit-math. There is a provision in goPos() to change torque on_the_fly. Leaving it on HIGH just uses more power. Note that motor power turns OFF when the motors have reached their destination. You can read more on this page. Single coil (lower power/torque) is called "wave drive.
Leo..

1 Like

And can you move by hand the stepping motor you have chosen? Remember it is a geared motor and so will be very hard to move.

It is not only power cuts you have to worry about it is also what happens when you want to turn the system off at night.

1 Like

I won't be moving the motor by hand, but instead I will move the object attached on top of it (the attachment is going to be easy to move).

Turning off at night shouldn't be a problem because rotations are initiated by external command like a switch (mentioned above in #46). So I will turn them off when there is no motion and all the steppers are at "home position".

I've ordered few TPIC6B595 and am waiting for them to arrive. My plan is to first try 4 steppers with 2 TPIC6B595 on a breadboard. If everything works well, I will start building with 32 motors.

How can I move away from breadboard when working on 32-motor design? I don't think deploying breadboards would be wise, right? It seems there are breakout boards like W19 design (5x Breakout PCB for TPIC6B595 shift register. Ideal for Arduino projects. | eBay), but cost+shipping is very high.

Alternatively, I noticed a massive TPIC6B595 board in @CrossRoads response on the other post:

The above seems custom made and has 328P which I am not looking for.
Are there such massive TPIC6B595 boards I can buy for reasonable cost?

No, things need to be soldered to be reliable. Try prototype board (strip board).
This one (click) could work.

With multiple chips you also can run into SPI fanout issues, so build quality must be good, with short traces and decoupling on each chip.

I would offer you the Gerber files for the boards I made (24 chips on a 10cm x 10cm board), but unfortunately I lost the hard drive they were stored on. @CrossRoads, who inspired me, is no longer with us because of Covid.
Leo..

Okay, let me read about prototype/strip boards.

Absolutely no idea what these SPI fanout issues are. They sound scary, especially the note about build quality. Will read more about this.

Thank you @Wawa for the offer. Actually, I am okay with learning new software; so do you think it would be wise for me to design the board directly instead of doing a prototype board? It would be a significant learning curve, and I would definitely need a lot of expert help to verify whether my design is heading in the right direction.

On a side note: I am talking way ahead about the board design phase even though I am currently just at the schematic diagram phase (haven't yet tried two TPIC6B595 + 4 steppers on a breadboard since I'm waiting for the delivery).

Oh, my deepest condolences. From the very little that I have seen so far, @CrossRoads has made remarkable contributions on this forum, and I have personally learned several things from their insightful posts.

The Arduino drives the latch/clock pins of all the TPIC chips, with a (default) frequency of 4Mhz. Wire inductance/capacitance and chip input capacitance will distort this high frequency signal to the point things won't work at the end of a chain any more. Short/neat wiring is key.

Fan-out was used in the TTL days. It was the number of inputs an output could drive. Not quite the same with Cmos chips, where wiring can be more important than number of inputs.
The protoboard I posted came the closest to what you want to built. Note that I updated that link.

Make a test set-up with two chips and four motors (GoPos() works with sets of four), and see if you can complete that. Take it from there.
Leo..

1 Like

Thanks @Wawa. The fanout issue makes a lot of sense.

Thanks a lot! This looks cool. I am assuming the holes are spaced properly such that they align with TPIC6B595 DIP pins? Their description does not say anything about spacing between holes (although they use the word "universal", which might mean something?). Also, it seems better to use DIP pin sockets to avoid soldering the DIP chip directly on the prototype board, am I correct? In this case I hope the DIP aligns with the hole spacing after the pin sockets are soldered.

Thanks, I will do this. Let me create a schematic diagram for this and post it here to verify.

Almost all through-hole parts have a 0.1 inch grid (2.54mm).
Leo..

1 Like

Here's the schematic diagram. I'd never made one before, and learning has been fun.

I'm not sure about the pins though. I basically looked at TPIC6B595 datasheet, the Arduino SPI documentation [SPI - Arduino Reference] (to match TPIC pins), and the stepper page you had provided (to match the wire colors).

But I had to do a bit of guess work when matching different terminologies, so would really appreciate to learn the mistakes here.

Then you should know that this chip pulls down only. That is it can't supply a voltage out of the chip. So I can't see how those motors will ever get any current flowing through them.

1 Like

Those motors have 5 wires. The centre tap being connected to a 5volt supply.
The TPIC pulls one or two of the four remaining motor wires to ground.

OP's drawing is wrong there. The centre taps are connected to ground instead of to 5volt.
Leo..

1 Like