Patch following music to control motor. work in progress ;)
You made more changes than simply that thing in "blue"
if you want to use 2 different sets of phaseshift lists,
don't recall them both and switch to either output.
Better pass dial to one or the other.
≠≠≠ you loadbang creation of that 2 colls/lists which are anyway embeded ≠≠≠
remove that and use embeded data saved in the patch.
merge message to coll could create that long lists ,maybe because live
is buggy, or you have 2 paches / devices open.
All that added if objects and reverse patch are not in my patch.
this looks very inefficient, whatever it does
hare is what I should do:
Only make better phase and reverse switching than that if objects...
Next difference between max and live is that all live GUI objects
suffer from live automation of parameters.
You should disable all off it including mappings of any kind
or replace all GUIobjects with max objects.
Hello.
Thanks for your answers.
With little things, all works as it should ;)
So, I delete inefficient things.
I switch between phase and reverse as you said.
But I had always the same problem with Live (too many datas). To fix it, I trig the two list each time I change between " same " and " different " phase.
Now I have always 14 datas.
To manage the movement with coherence and beauty , I changed in the patch [all-controls] sel 1 to sel 10.
With these changes, every time you activate a feature, the movement is always in tune. Whenever you enable features like: same, different, reverse, phaseTriggerSwitch, align,... the motors will always get the same phase offset between them.
I am very satisfied.
Thank you infinitely.
Well , glad you are happy, but sorry, I am not ...
because you for no reason rewrite both colls every time you bang that "same / different" switch.
you made big mistake here: @ embed 1 with space is invalid argument .
colls loose their data on close.
about the last version of your patch:
As first, gate should be switched on or off, NOT banged !
NOT LIKE THIS :
BUT LIKE THIS:
you have same = coll list and switch is outputting 1,
so switch must be reversed !
AGAIN - do not clear and repopulate that 2 poor colls !!!!
they have data embedded, and only reason to repopulate them would be if you change
their lists !
.................................................
Now to that phase switch.
it does NOT trigger but turns gate on or off !!!!
this switch :
is controling that gate in the screenshot.
now what exactly do you want to do ?
1~ if you want to OPEN THAT GATE only when switch is ON
and only WHILE motor 10 is getting triggered ?
And CLOSE THAT GATE when any other motor gets triggered ?
or :
2~ When switch is ON it has to wait for motor 10 to get activated and
KEEP GATE OPEN till switch gets OFF again ?
you can test both here:
I think you want option 2, all you need is allready in patcher all-controls :
sel 10 from counter and input from phase switch.
Good evening,
Indeed, I know it's stupid to reload both colls each time, but it's the only method so that it doesn't bug in Live.
Also, I need to trigger the phase gate/Trigger Sw only once when the motor is at 10. Then If I want to close the gate I press phase/Trigger Sw and it will close the gate when the motor is at 10. So I keep my system.
Also, I changed this.
This way, when there is no more sound signal, the gate is closed.
The last new feature is enable/disable rev counter. So I added a gate to the rev counter
Thank you for your views
Good day
look at this :
1~ simpler phase switch, you can build it into subpatch
2~ change 0. is not controlling the gate at all, try to move float 0. > 0. and back ....
sel 0. allready blocks output of meter~ when there is no input signal.
Good evening,
I wish you the best best for this very square (and not scared) year!
I changed the patch as you said in the last post.
In addition, I changed the use of button rotStep as an adder to the rev counter. If the button reaches three then rev counter[3] adds 1.
I will control rotstep with an LFO from Live. As below
Finally, I wanted to calculate the real position of the motors according to their position and the number of rotations. But when the motors make a turn, the real positions are poorly computed as we can see in the console highlighted in blue. Computing is bad because rev couter bugs.
In my example I made a continuous rotation. So speed should be always the same.
I hope the solution will be easy for you. Thanks teacher ;)
I wish you also all the best in new year !
to be honest, I allways need quite some time to shape your uploaded patches
to try to understand what is the state, and what is it that you ask for.
Most difficulty is that all your patchcords get routed (fragmented) in a way
that it is hard to follow where they go.
You did actually not fix switching of phases at all.
To start with, here is last working patch with proper phase switching
and replaced colls. lists are now in 2 umenus.
switch itself is in all-controls patcher, where it should be.
......
Now to that new stuff ...
to start with :
can you use this extract to patch and explain using ONLY this objects
what you really want from that LFO . "... it needs sound ???"
I want to know what is that scale with float ???? doing there ?
and what should output of that LFO/BEAP represent ?
think that rotStep is endless dial usng INTS only !
and explain also what should effect be when CW vs CCW...
..........................
that rotation counter is a fake and will remain a fake.
rotation is absolute value and rotation counts no matter if rotated cw or ccw,
if you have a wheel, and it turned 100 times in whatever direction
2r π * rotation -> you have traveled distance.
your rotation is imaginary and I don't know
how can you really count the movement.
if you would really use arduino and insert rotation report from motors and report it
then ok.
I took a bit of time to run your patch in live 11.
Or better say my last uploaded patch .
I don't really understand the logic with all this phase shifts, rotations etc.
but anyway phase offset needs a little change to work properly.
here is patch with changes
Thanks!
2 umenus work perfectly!!
I use integer to trig rev counter as I explain here.
Actually I will use a signal from Ableton Live.
As you implicitly said, we need to have functionality to trigger the cw/cww button if "rotstep" turns to cw/cww.
But the important thing I would like to fix is the manner to compute the position of the motor.
I tried in the last patch you have just made VIGER FIX 8jan2025b.maxpat
I would like to fix the bug, that I think, comes from the rev counter. As you can see highlihted in blue, positions are 182399, 185599, 182415.
The middle one is not good.
ps : how did you transform coll list to umenu ?
I simply dumped coll to prepend append.
That dial had originally -9 ~ 9 range
do you now want to reduce it to only 0 - 10 ?
to use it's full range you need to scale 0. 1. 0 19
I am afraid I don't understand how do you want to compute real motor position.
Yes . dial had originally -9 ~ 9 range
Now dial is 0 ~ 9 range.
I scale signal from 0. to 1. like that : scale 0. 1. 0. 10.
_________________________
I would like to compute position of my 3200 stepper motor like that.
I multiple * 100 the number of the live dial which is from 0. to 32.
So I have only integer from 0 to 3200.
Then I add the number of rev counter * 3200
So if live dial is 16.52 and rev counter is 2 => 16.52 * 100 + 2 * 3200 = 8 052
the motor has made the 8052 th step.
Ok - I get it about rotation dial.
Will change it in my copy of the patch.
Maybe you have to rethink rotation counter.
truth is that you send all kinds of values
which add, subtract, exchange with different channels etc etc
to a single % 32 modulo at the very end.
rule is a simple one :
~ if CW and current value is lower then previous one - we add 1 count.
~ if CCW and current value is higher then previous one - we subtract 1 count.
Do you want to use that, no matter what you send to that modulo 32 ?
If yes, then rotation counter can be simplified, and take no care
if you rotated list, shifted phases, added whatever.
ONLY respect that 2 values : previous -> current.
You must understand that your system has nothing to do with real rotation,
which must move from point A to point B, not jump.
Ok.
Yes I do with ONLY respect that 2 values : previous -> current..
Thanks ;)
That is not the case now .
test this
rotate dial
Good.
I will use this method for a specific use.
Now it should great to have a default use of rev counter.
We have to add a feature that automatically discriminate the way of rotation dial .
If it is CW and dial rotate respectively from 16.~ 31.99 to 0 ~ 16, then counter incremente 1.
Or it is CW and dial rotate respectively from 0 ~ 16 to 31.99 ~ 16 then counter decremente 1.
Now you see what I mean
Either use real deal or cheat…
What do you mean with specific use ?
But what I really want to know:
Are you driving any motors with this at all ?
Why don‘t you use 360. degrees dial
and center it at top = 0 ?
instad of 32 ?
I think I will use this method for a specific use when I will rotate data with [zl.rot]
But I don't know really how I will do for the moment.
Yes I drive motor with an Arduino, a Teensy actually.
I need to modulate speed and acceleration.
That's why, for today, I really need to get real position.
So if I can automatically set cw or cww, it will work fine.
Yes we can use 360. degrees dial and center it at top = 0
Then I will have to scale live dial like that
[scale 0. 360. 0 3200]
If you use real motors then you can‘t
jump arround with values.
If you have a motor placed at 120
degrees and want to move it to
330 degrees , you have to decide
to rotate it CW 210 or CCW 150
Yes. This is the thing I have had to decide for a long time. But for now, I'm going to use your patch that you just made to calculate the position.
This system is functional because for the moment my motors go only in CW or CWW.
For another use, another rev counting system can be developed. We could calculate the two absolute distances between the new position and the previous position.
Then we will always use the smallest value
We have a motor placed at 120° to move to 330°
Here it is 210° and 150°
We will therefore use 150°
In this case we will go counterclockwise.
In another example
If we were at 330 and we have to go to 120°
the calculation of the distance is still 210° and 150°
We use 150°
In this case we will go clockwise.
In another example
If we were at 10° and we have to go to 160°
the calculation of the distance is still 150° and 210°
We use 150°
In this case we will go clockwise.
I think I will adapt movement of dial in order to move less than 180°/step.
I thought from the beginning that you abandoned motors and use the dials
just for some visual effects. Because one can't run motors synced to dials
using that jumping values.
What are the motors and how do you control them ?
You can jump in software to whatever value/position,
but motor takes some time to reach it also
respecting CW or CCW direction.
For me, that rotation counter is simply useless.
As well as to use it to calculate acceleration or speed.
and there is no need to use 360 float dial,
if you extend it to 36. float. it is easy to scale it at output or in arduino code.
I would replace that live dials with dials with endless rotation
Yes you are totally right.
Could you show me how you incremente position from endless rotation ?
and decremente....
And I will need to multiply rotation *3200 and add position from endless rotation.
Could you do it please ?
I use your method to count revolution in the last patch you have made.
it works fine. I keep this method for today because I have to make a video of my installation today. Below the test with the first live dial
But it 's not what you have just said this morning
I am really willing to help you, but simply don't know how.
what are you trying to do ?
Do you want to sync a motor position with dial position ?
Rotation count makes no sense unless you want to
calculate total travel of a wheel.
like with a car : wheel with 50 cm diameter has one rotation length of 157 cm.
rotate it 10 times + 30 degrees = 1583 cm.
but that is not what you need , or ?
Forget this rotation counter.
It makes no sense.
Hello,
Yes I want to sync a motor position with dial position!
I think we just have to add or subtract the number of steps, to the previous position to control the motors.
If we are in CW then positionMotor=positionMotor+positionDial
If we are in CWW then positionMotor=positionMotor-positionDial
Indeed, we don't need rev counter anymore!
Below I explain how the motor should react:
Let's say that the movement between the current position and the previous position is always less than 180°.
If the dial goes from 120° to 180°, the motor will do 60 * 3200 / 360° = 533.333.
so it will have to do 533 steps clockwise.
Then, if the dial goes to 180° at 1°, the motor will do 179 * 3200 / 360° = 1591.11
so it will have to do 1591 steps counterclockwise.
Finally, if the dial goes from 1° to 182°, we choose the shortest path, which is 179°.
because the two calculations of the angular distance are
182-1= 181°
1-182+360 = 179°
So the motor will make 1591 steps counterclockwise.
I would like the motors to be as responsive as possible. I want, if possible, the speed and acceleration to be proportional to the distance traveled (the number of steps).
Thank you very much
In case you want to have dials and motors synced,
I think you have to go from motor specs and translate that to
controls in live that motor can follow reliably.
What speed motor can do in what time ?
when you say we don't need rev counter , you mean rotation counter all together ?
If you now wan't to do this all properly, what about CW/CCW switch ?
now all has to be translated to 360° instead of 0. - 32 float.
then, maximum change must be less than 180°
what libs do you use to run which motors ?
why 3200 steps ?
if it is a step motor than it has specs.
usually 200 steps per full turn, or 1.8° per step.
Post them, as well as arduino code.
live dials can move as fast as possible, motor not.
to run stepper motor one has to defins direction, speed
number of step to go etc etc.
Motors themself would react so or so depending on weigth they have to move ...
so many factors.
And you have to reset motor position to be able to tell it to go somewhere
that equals dial position.
The motors I have are Nema 23 which are 1.8° for 200 steps.
The holding torque is 1.2 N.m
I divide the step size by 16 thanks to my good digital drivers.
So I have 3200 steps and a precision of 1.8/16 = 0.113 degrees per step
This way the motors are driven silently and without tremors
I think counting revolutions is no longer useful if you add or subtract the engine positions from the previous positions.
On the other hand, I want to be able to control the directions of global rotation, so we keep the current configuration of the patch with CW and CWW
For the Arduino part,
There is no need to control the direction of rotation with my digital drivers
I use the acceleStepper library
You can modulate the speed and acceleration
I rotate a 30 gram aluminum bar on which I attached an 8*32 LED strip
I also have a small box with a fairly heavy battery (the same as for electric cigarettes) which I fixed on the aluminum bar as close as possible to the axis of rotation of the motor.
In total I'm running something weighing 120 grams.
So, absolutely no sudden movement is necessary.
I can get the motors to run at two revolutions/sec
A maximum acceleration of 1 revolution/sec seems more than sufficient to me.
Here the Arduino code
#include <AccelStepper.h> // Define a stepper and the pins it will use
#define NBMOTEURS 10
#define NBDATA 34
#define NBPASPARTOUR 3200 // numberOfStep/round
long ABC[NBDATA] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; // Teensy has to parse 34 ints fromMaxForLive
//position == data from 0 to 9
//speed == data from 10 to 19
//acceleration == data from 20 to 29
//other data from Max4Live == data from 30 to 33
#define STEP 1//. set driver to subdivise step.
// 800-->Mode 1/4 pas MS2 sur ON
// 1600-->Mode 1/8 MS1+ MS2 sur ON
// 3200--> Mode 1/16 MS3 sur ON
// 6400--> Mode 1/32 MS1+ MS3 sur ON
// Teensy (better than Arduino)
const uint8_t PINDIRECTION[NBMOTEURS] = {6, 9, 12, 26, 29, 32, 34, 37, 39, 41 };
const uint8_t PINSPEED[NBMOTEURS]= {5, 8, 11, 25, 28, 31, 33, 36, 38, 40 };
const uint8_t ENABLEPIN[NBMOTEURS]= {4, 7, 10, 24, 27, 30, 133, 135, 139, 142};
// Define a stepper and the pins it will use
AccelStepper stepper[ NBMOTEURS] = {
AccelStepper (STEP, PINSPEED[0], PINDIRECTION[0]),
AccelStepper (STEP, PINSPEED[1], PINDIRECTION[1]),
AccelStepper (STEP, PINSPEED[2], PINDIRECTION[2]),
AccelStepper (STEP, PINSPEED[3], PINDIRECTION[3]),
AccelStepper (STEP, PINSPEED[4], PINDIRECTION[4]),
AccelStepper (STEP, PINSPEED[5], PINDIRECTION[5]),
AccelStepper (STEP, PINSPEED[6], PINDIRECTION[6]),
AccelStepper (STEP, PINSPEED[7], PINDIRECTION[7]),
AccelStepper (STEP, PINSPEED[8], PINDIRECTION[8]),
AccelStepper (STEP, PINSPEED[9], PINDIRECTION[9]),
};
// Receive with start- and end-markers combined with parsing
const byte numChars = 200;
char receivedChars[numChars];
char tempChars[numChars]; // temporary array for use when parsing
// variables to hold the parsed data
char messageFromPC[numChars] = {0}; //or 5 doesn't change anything
int enableDriver1= 0; // test enable driver. I don't need but I wanted to test
int led = 13;
boolean newData = false;
// CHECK NUMBER OF ROUND AND GOOD MOVEMENT
int testOneRevolution;
void setup() {
Serial.begin (115200);
for(uint8_t i = 0; i < NBMOTEURS; i++) {
stepper[i].setMinPulseWidth(5); //****************************************if TEENSY's clock is very fast, motor needs a little pulse
// Initialisation des pins moteurs
pinMode(ENABLEPIN[i], OUTPUT);
digitalWrite(ENABLEPIN[i], OUTPUT);
digitalWrite(ENABLEPIN[i], LOW);
pinMode(PINDIRECTION[i], OUTPUT);
digitalWrite(PINDIRECTION[i], OUTPUT);
pinMode(PINSPEED[i], OUTPUT);
digitalWrite(PINSPEED[i], OUTPUT);
stepper[i].setMaxSpeed(NBPASPARTOUR*2); // 6400 step*sec^-1
}
testOneRevolution=NBPASPARTOUR;
ABC[NBDATA-2] =1; // ratioSpeed. // maybe I will use
ABC[NBDATA-1] =2; // ratioAcc // // maybe I will use
enableDriver1 =1; // enable driver 1 // just to test
for (int i =0; i<NBMOTEURS; i++) // setPositionToMotor
{
ABC[i]=testOneRevolution; //
stepper[i].moveTo(ABC[i]);
stepper[i].run();
}
for (int i =NBMOTEURS; i<NBMOTEURS+10; i++) //setSpeedToMotor
{
ABC[i]=600;
Serial.print( " speed " + (i)); Serial.println(ABC[i] );
}
for (int i =NBMOTEURS+10; i<NBMOTEURS+20; i++) //setAccToMotor
{
ABC[i]=300;
Serial.print( " acc " + (i)); Serial.println(ABC[i] );
}
Serial.print( " SPEED "); Serial.println(600_steps_made_in_one_sec);
}
void loop() {
for(uint8_t i = 0; i < NBMOTEURS; i++) {
stepper[i].setMaxSpeed(ABC[i+10]); // speed is set from Max
stepper[i].setAcceleration(ABC[i+20]); //acceleration is set from Max
//SPEED MAX
if ( 3200+ (1 * ABC[i+10] *1.0*ABC[NBDATA-2])>= NBPASPARTOUR*2)
{
stepper[i].setMaxSpeed(NBPASPARTOUR*2);
}
}
recvWithStartEndMarkers(); // receive data like that <10,258,.....,-32> // then split them
if (newData == true) {
strcpy(tempChars, receivedChars);
// this temporary copy is necessary to protect the original data
// because strtok() used in parseData() replaces the commas with \0
parseData();
newData = false;
}
moveMotorSetOneByOne(); // i control motor differently because they are not linked to the driver in the same "way of rotation"
}
void recvWithStartEndMarkers() {
static boolean recvInProgress = false;
static byte ndx = 0;
char startMarker = '<';
char endMarker = '>';
char rc;
while (Serial.available() > 0 && newData == false) {
rc = Serial.read();
if (recvInProgress == true) {
if (rc != endMarker) {
receivedChars[ndx] = rc;
ndx++;
if (ndx >= numChars) {
ndx = numChars - 1;
}
}
else {
receivedChars[ndx] = '\0'; // terminate the string
recvInProgress = false;
ndx = 0;
newData = true;
}
}
else if (rc == startMarker) {
recvInProgress = true;
}
}
}
//================================================================= RECEIVE 34 DATAS FROM MAX_FOR_LIVE
void parseData() { // split the data into its parts
char * strtokIndx; // this is used by strtok() as an index
strtokIndx = strtok(tempChars,","); // get the first part - the string
for(uint8_t i = 0; i < NBDATA; i++) {
ABC[i] = atoi(strtokIndx); // convert this part to an integer
strtokIndx = strtok(NULL, ","); // this continues where the previous call left off
}
}
void moveMotorSetOneByOne(). // sometimes there is -ABC[9] or ABC[7]... because my motors are not plugged in the same rotation way.
{
stepper[9].moveTo(-ABC[9]);
stepper[9].run();
stepper[8].moveTo(-ABC[8]);
stepper[8].run();
stepper[7].moveTo(ABC[7]);
stepper[7].run();
stepper[6].moveTo(ABC[6]);
stepper[6].run();
stepper[5].moveTo(ABC[5]);
stepper[5].run();
stepper[4].moveTo(-ABC[4]);
stepper[4].run();
stepper[3].moveTo(-ABC[3]);
stepper[3].run();
stepper[2].moveTo(-ABC[2]);
stepper[2].run();
stepper[1].moveTo(-ABC[1]);
stepper[1].run();
stepper[0].moveTo(ABC[0]); //
stepper[0].run();
}
Well it is your decision how to drive motors, but think that
you are allways reacting to what value a dial has.
motor will need some time to get where dial is
using your complicated control
which is more suitable to run motors alone
then to chase external absolute position.
that will definitelly put motors out of sync quite soon.
two revolutions/sec meany maximum 120 RPM.
your patch produces much faster movements.
did you consider using
mystepper.moveTo(targetPosition);
....
I would have constructed all this a bit different,
use phasor~ to rotate using speed derivated from audio level,
and to create that offsets and what you call phase shifts
use delayed output.
every time you align or rotate the list,
jump arround, pause the process , position the list, continue.
And all of that respecting motor capabillities.
in this case 120 RPM
mystepper.moveTo(targetPosition);
what is the difference with stepper[9].moveTo(-ABC[9]); ?
-ABC[9] is the target position.
You mean, I have to send position continually with data from [phasor~]. With this object I will can compute speed more easily ?
Can you show me a patch please to control two motors? with delayed output and all the processes you pointed out.
Ha, ha that would be a good deal of work.
I mean not to run phasor, but to play this game with rotations,
offsets etc.
That are the problems.
I will soon post example using phasor to drive dial/motor using audio level.
a very simple starter
it looks perfect! I hope it will be easy to add the others features. Sound and mouvement will be as a maximum tuned.
I'm very happy ;)
Ah, ok, now please think about max speed your motors should move.
I think man thing now is to decide which objects
to use in signal and which in non signal domain
to play with 10 motors offset , speed etc.
You must insert change 0. and speedlimit at end to tame
serial data flow and motor position refresh rate.
if I understand correctly you don't need to send anything else but position - list of 10 floats.
you can simplify arduino code quite a bit.
you said You must insert change 0. and speedlimit at end to tame
you speak about the last patch you made ?
I need to send speed and acceleration if I want to control motors as smooth as possible.
Here the patch to send data to Arduino.
I added [change]. because we will send integers
You can see that adjust motor manually (because I don't have encoder to automatically align motor)
I adapt a patch you have made for me.
Last patch had that after one dial only - the one that could rotate phase.
I see - you allways send full list instead of individual sliders,
similar as DMX, collect the list,
but bang it at acceptable interval ... all ok.
Ok. ;)
Will you be able to add all the options (rotation, phase shift gate, etc.)? because I'm not sure I know how to do it well.
And a quick question how do we add a position to the previous one. like the += operation?
like that ?