Help with Kinetic Art Project

Gentlemen, It's the never ending story of us asking questions and not giving enough info, so you guys have to guess. Sorry but it's only to avoid long threads.

As to where I am, Pls see:

@PaulRB Cogs were my first choice. All the shafts go through the frame.
I have some problems. My gears were not CNC'd but 3D printed and are not fine like the original one, so they have a little "play". The white parts of the gears were printed separately, as a half circle, and I had to glue them to the black gears, thus loosing some precision. After a lot of trials and throwing away gears and frames (life is hard for rookies) I found out that the gears can not be aligned in a strait line in order to turn. They kept getting stuck.
My panel works, i.e. it turns , but as you can see in the video is not precise.

So, I thought why all the trouble ? I'll just 3D print the white half circle ( the back ground is black anyway) stick them to a motor, and turn them. Then make a full disc in the back of each to place a magnet for the sensor.
Hope you have the whole picture now. Thank you all

oops, I noticed the video won't play ?!? Pls try :

Yes, I see the problem. And I can see how attaching a motor to each disk would get around that problem. But you would need a home sensor on every wheel, and you couldn't drive the motors with the same signals, because that would prevent you from getting each to is home position.

To my mind, the biggest problem with using a motor for every disk would be that somehow the cleverness and coolness of the original cog design is gone. For me, what made it so cool and clever was that it did what it did with such a simple mechanism. It seems too simple to make the patterns it does, and yet it does it. That was the surprise. But with a motor on every wheel, of course you can do whatever you like or want. A complex mechanism making complex patterns is to be expected, the surprise is gone.

Do you get what I mean?

I get your point Paul.
But after all the work I hate to give up.
I'm searching the net to see if I can find a large cog for the motor with 5 mm bore that could match a 4 mm bore cog for the gear. Underneath each gear I have placed 2 ballbearings to help smooth their turn and keep them in place.
But the biggest problem remains allignment.

Not really. If I could manage to control all the steppers in synch with the same signal (with help from you guys) then I could have a large hidden disc with 10 or 12 magnets for the sensor stops. No homing needed, just stop at different patterns. Am I wrong ?

Brilliant idea, wish I'd thought I'd that

Gentlemen, I've decided to use both the "cog" mechanical approach for the board I already have and make a new board with 41 steppers.
I'll use the cheap 28BYJ steppers. As mentioned before, it seems, I have to use shift registers. I did some "home work" on them, tried to find tutorials but I'm back to square one.
Can you pls guide me trough type of shift register / port expander to use ?
For example I read MCP23017 with I2C or MCP23S17 which uses the SPI interface that operates at 10MHz , much faster than I2c. Or 74HC595 or TPIC6B595. These are all over my rookie head and I don't know which one to use.
Can I use A4988 drivers with mod 28BYJ's with these shift registers? Or use their old ULN2003 ?
I'd like to avoid having to add transistors capacitors etc etc.
Pls remember I need all servos to turn together, at slow speed, and only clock wise. Synch is the most important aspect !
Is it possible to drive all the steppers with one signal pin from Arduino ? if yes, how ?
Thank you.

SPI Vs i2c does not matter in your project. Both are way faster than any motor.

If you use 74hc595, mcp23008, mcp32017, mcp23s17, pcf8574, pcf8575, then you will need one of those uln2003 driver boards for every motor.

If you use tpic6b595, you won't need the Uln drivers. This could save you a lot of clutter and wiring and if you can buy the motors without the Uln boards, save money and reduce waste.

Not sure about A4988. It is a bipolar driver and 28BYJ is a unipolar motor. It may be possible to wire 28BYJ for a bipolar driver. But you would need a A4988 for every motor, and also shift registers to drive the A4988s, so lots of extra expense and complexity for little benefit I suspect.

I still think you are wrong about that. To home each motor you will need to have them turn independantly as well as together, and have a home sensor for each disk.

3 pins for 74hc595/tpic6b595, 2 pins for mcp23017/pcf8575 etc.

With 74hc585/tpic6b595, they can be daisy-chained, so data goes from Arduino to first chip, data out from first chip goes to second chip etc. Clock and latch signals are shared by all chips.

With mcp23017, pcf8575 etc, the data and clock signals are shared by all chips, and each chip is given a different "address" on the i2c bus by wiring their "An" pins in different ways.

@PaulRB Thank you.
I tried to order some TPIC6B595 but find different types : TPIC6B595N ** or without the "N" ? And find SIPO (serial in parallel out) or PISO, PIPO or SISO. Which one do I need ?
I read most of the posts on the net about the same problem I have to better understand what I'm doing. In one discussion I read that if you need to move the steppers in one direction only, then you could use A4988 drivers hooking up all DIR signals to GND or 5v (thus saving pins) along with a multiplexer, but it didn't explain how.

1 Like

The "N" simply refers to the DIP (Dual In Line) package for through hole mounting. You really need Wawa's boards which use the SOIC chips, otherwise it will be quite a nightmare.

You need the TPIC6B595! It does the job properly. Wawa is no fool. :roll_eyes:

You have given a "dropbox" link, not a useful URL.

I tried Wawa's boards n times, tried them today also before posting. I hooked up everything as his instructions, uploaded his code, NO motor movement !
Time ago I even wrote him an email, no reply. These boards are really nice I WISH I could use them.
Sorry about the link, I thought I corrected that in post 22, it opens for me.

Well, as I can see neither his instructions or his code or your layout, I cannot be of any help. :cry:

I tried to upload a photo of the board and his hand written instructions but keep getting "InvalidAccess".

please see : Creating The BMW Kinetic Sculpture - #275 by Wawa
There you can see the boards and his code.

I'm having trouble reconciling the above with:

Sorry to hear that.
I tested the boards extensively before shipping, so I expect you have a connection or power problem. Please upload pictures showing all the connections to the Arduino.
Leo..


Leo, it's only my fault and not your's. I'm still in debt to you for your help and kindness. As you can see in the photos I connected everything as your instructions. Here's your code I'm using :

/*
 Nano | TPIC6B595
   5V | 2 (VCC)
  GND | GND
   D8 | 8 (SRCLR)
  D10 | 12 (RCK)
  D11 | 3 (SER IN) of the first chip
  D13 | 13 (SRCK)
      | 9 to GND
      | 10, 11,19 to GND
      | 18 (SER OUT) to 3 of the next chip
*/

#include <SPI.h>
const byte motors = 48; // sets of four motors
const byte clrPin = 8; // TPIC6B595 SRCLR pin8
const byte latchPin = 10; // TPIC6B595 RCK pin12
const byte rampSteps = 7; // accel/decel steps
byte rampDelay[motors]; // accel/decel delay between steps
byte lag[motors]; // speed reduction
int velocity[motors]; // signed, for direction
int nowPos[motors], newPos[motors]; // int is 16 rotations max (2.5m string with a 50mm dia wheel)
unsigned long prevMillis, prevMicros, interval; // timing
byte val[4]; // TPIC write bytes
bool torque; // reduced during homing
byte sequence, index; // patterns, motor index

void setup() {
 SPI.begin();
 pinMode(clrPin, OUTPUT);
 pinMode(latchPin, OUTPUT);
 digitalWrite(clrPin, HIGH); // clear all shift register data
 for (byte i = 0; i < motors; i++) nowPos[i] = 1024; // homing all motors 1/2 turn
}

void loop() {
 switch (sequence) {
   case 0: // break free from the top, all motors
     if (nowPos[0] == newPos[0]) { // finished homing
       for (byte i = 0; i < motors; i++) nowPos[i] = -128; // 1/16 turn
       torque = true; // was low power during homing
       sequence = 1; // case 0 is not called anymore
       prevMillis = millis(); // so mark here
     }
     break;
   case 1: // 4.5 turns down, all motors
     if (millis() - prevMillis > 8000) {
       for (byte i = 0; i < motors; i++) newPos[i] = 9216; // 4.5 * 2048
       sequence = 2;
     }
     break;
   case 2: // all return to zero, one after the other
     if (millis() - prevMillis > 30000 + interval) {
       if (index < motors) {
         newPos[index] = 0;
         interval += 500;
         index += 1;
       } else { // when done
         index = 0;
         interval = 0;
         sequence = 3;
       }
     }
     break;
   case 3: // run sequence(s) again
     if (millis() - prevMillis > 75000) {
       prevMillis = millis();
       sequence = 1;
     }
     break;
 }
}

Hello again folks,

My cogs, and sensors have arrived. I'm using 2 Nema 17's and an Arduino Uno shield v3. I've hooked up a HC-SR501 motion sensor (to detect motion and start moving the gears) to X+ end stop pin and a Hall sensor (to stop the motors) to the Z+ end stop pin of the shield.
I'm making a hidden large disk ( 3 or 4 times bigger than the larger gearwheel) that will have 7-8 magnets on it. Each magnet for one stop to last 3 minutes.

I have never used this hardware set up so I have 2 questions Please:

  1. I'm using the sensors with Arduino's 5v, without any resistors and not as PULL_UP. It works but I'd like to know if that's the correct way.

  2. I find myself with the Hall effect magnet triggered at power up. Check the PIR
    sensor for presence, if yes, move one step at a time until I hit a magnet, then
    stop for a couple of minutes. Then check the PIR sensor again, if no presence
    then just stay where I am, else move to the next magnet.

I've written some code, it detects presence, moves away from the magnet on start but will not move anymore since the Hall effect sensor is triggered. Where am I goofing ?


const int stepX = 2; // X.STEP
const int stepZ = 4; // Z.STEP

const int MoveSens = 9;  // HC-SR 501 Movement Sensor (Pin X+)
const int STopSens = 11;  // Hall sensore stop  (Pin Z+)

void setup() {

  Serial.begin(115200);

  pinMode(MoveSens, INPUT);
  pinMode(STopSens, INPUT);

  pinMode(stepX, OUTPUT);
  pinMode(stepZ, OUTPUT);

}

void loop() {

  int MoveSensVal = digitalRead(9);  //  value for HC-SR 501 Movement Sensor

  if (MoveSensVal == HIGH) {

    Move();

    int StopSensVal = digitalRead(11);   // Value for Hall Effect sensor STOP

    if (StopSensVal == HIGH) {
      Move();

    }

    else
      delay (10000);
  }
}


void Move() {

  for (int x = 0; x < 1; x++) {
    digitalWrite(stepX, HIGH);
    digitalWrite(stepZ, HIGH);
    delay(10);
    digitalWrite(stepX, LOW);
    digitalWrite(stepZ, LOW);

  }

}

Never mind folks, I took a different approach and it works fine.
One PIR sensor, one Hall effect sensor and 1 magnet.
At power up, I home steppers using the Hall effect sensor. Then, since I have fixed stop points, I put them in an array. Then generate a random number, which points to the position in the array, and move there every time PIR sensor is triggered.
Thanks all for your help.
I'm posting my code, it might help someone.


const int stepX = 2; // X.STEP
const int dirX = 5;

const int stepZ = 4; // Z.STEP
const int dirZ = 7 ;

const int MoveSens = 9;  // HC-SR 501 Movement Sensor (Pin X+)
const int STopSens = 11;  // Hall sensore stop  (Pin Z+)

int CurrPos;
int NewPos;

void setup() {

  Serial.begin(115200);

  pinMode(MoveSens, INPUT);
  pinMode(STopSens, INPUT);

  pinMode(stepX, OUTPUT);
  pinMode(dirX, OUTPUT);
  pinMode(stepZ, OUTPUT);
  pinMode(dirZ, OUTPUT);

    Home();   //  Home Stepper X and Y
    delay(5000);

}

void loop() {

  int MoveSensVal = digitalRead(9);  //  value for HC-SR 501 Movement Sensor

  if (MoveSensVal == HIGH) {

    NewPos = Generate_Random_Position();

    if (NewPos != CurrPos) {

      Serial.println("New Position = " + String(NewPos));

      GoToTarget(NewPos);
     
    }

  }

}


void Home() {

  digitalWrite (dirX, LOW);  // Turn CW
  digitalWrite (dirZ, LOW);

  for (int n = 1; n < 2000; n++) {

    int StopSensVal = digitalRead(11); // Value for Hall Effect sensor STOP

    if (StopSensVal == HIGH) {

      for (int x = 0; x < 1; x++) {
        digitalWrite(stepX, HIGH);
        digitalWrite(stepZ, HIGH);
        delay(10);
        digitalWrite(stepX, LOW);
        digitalWrite(stepZ, LOW);

      }
    }
  }

  CurrPos = 0;
  Serial.println("Home Position = " + String(CurrPos));
}


int Generate_Random_Position() {

  int RandNum;
  int TargetPos;

  int Positions[] = {0, 150, 230, 350, 400, 800, 900, 950};

  randomSeed(analogRead(0));  // generate a random number
  RandNum = random(0, 8); 
  delay(50);
  TargetPos = (Positions[RandNum]);

  Serial.println("Random Number = " + String(RandNum));
  return TargetPos;
}

void GoToTarget(int T) {

  Serial.println("Moving to Position .... " );

  if (CurrPos > T) {
    digitalWrite (dirX, HIGH);  // Turn CCW
    digitalWrite (dirZ, HIGH);
  }
  else {

    digitalWrite (dirX, LOW);  // Turn CW
    digitalWrite (dirZ, LOW);

  }
  for (int x = 0; x < T + 1; x++) {
    digitalWrite(stepX, HIGH);
    digitalWrite(stepZ, HIGH);
    delay(10);
    digitalWrite(stepX, LOW);
    digitalWrite(stepZ, LOW);

  }
  CurrPos = T;
  Serial.println("Moved to Position = " + String(CurrPos));
delay(10000);
 
}