[WIP] Motorized camera crane ( stepper + arduino based )

Hi !
Fisrt of all i apologize for my bad english. ( By the way I'm not sure if I'm on the good section )

My friend and I are building a Motorized Camera Crane. My friend is good at welding and stuff, and I'm studying electronics at school.

So i've already made some Stepper controllers with PLDs, but i wanted to use an arduino for this project ( easier to upgrade the whole thing than with PLDs )

The frame is near finished, and i'm stuck at programming it.

I don't Know what motor i'll use, unipolar or bipolar, but now i'm designing the speed control interface.


So ! I've got a potentiometer ( will be replaced by a joystick ) , a led to visualize the direction ( on = CW , OFF = CCW )
I've also got a buzzer to hear the sound ( and visualize the signal on my oscilloscope )

I want the the frequency to go up with the absolute value of my pot ( the direction led is actived by whether or not my pot is not on the center ( by using "if else" ) )

I don't want to use the STEPPER library, because it uses the "delay" fonction, and gives latency on the control of frequency. Maybe if i tweaked it ?

So i used the " blink without delay " sketch to create my frequency.

Here's the code :

float sensorVal       = 0;    // store the value coming from the sensor
int sensorPin = A0;    // select the input pin for the potentiometer
int ledPin = 7;      // select the pin for the LED
int ledState = LOW;             // ledState used to set the LED
long previousMillis = 0;        // will store last time LED was updated

void setup() {
  // declare the ledPin as an OUTPUT
  pinMode(ledPin, OUTPUT); //  
  
}

void loop() 
{
  
  // read the value from the sensor:
  sensorVal = analogRead(sensorPin);  // Reading the joystick
  sensorVal = map(sensorVal, 0, 1024, -500, 500); // setting the "0" 
  sensorVal = 2000/ sensorVal; // F=1/t  with a multiplier to reduce the max freq
  
 // Generating the temporary clock for the future stepper library 
  unsigned long currentMillis = millis();
 
  if(currentMillis - previousMillis > abs(sensorVal)+1) // Abs() gives me the absolute speed  
    {
      previousMillis = currentMillis;   
        
      if (ledState == LOW) 
        ledState = HIGH;
      else
        ledState = LOW;
      digitalWrite(ledPin, ledState);  //End of the clock                
    }
    
}

It works like a charm at low speeds ( unlike with stepper lib )
but at high speeds, the frequency's not constant ( i can hear it and mesure it with the oscilloscope )

I tried to " microseconds() " but whithout good results ( like the frequency going really high and random when the pot is near 0 )

Thanks you in advance !

Pictures soon :slight_smile:

What is the maximum frequency are you trying to achieve? At what sort of frequency does this problem show up?

Actually i don't really know since i haven't got the motors. But at school i was able to drive a motor near 200Hz.

On my arduino, with the sketch i've uploaded ( i just added a serial print, to read the abs(speed) value )
I'm doing 125Hz quite well, i recieve 7.514 which is rounded to 8 due to the milis() restrictions .
When i increase the frequency ( decreasing this value to 5 ) the frequency oscillates between 5ms and 6ms ,

I have to increase the precision of these values.

Now i've tried with micros() and multiplying "sensorval" by 1000 ,

I've got the same problem, sensorval is good, but with small values of time, i cant get "intermediate" frequency, it's like it still rounds my value. So, at high speeds, the frequency is like doubled, each time i move the pot.

That period is short enough that you should probably be using micros rather than millis.

I feel sure there must be a better timer-based solution for output at those frequencies and I'd expect to find that a standard library implementing it.

If you continue with the approach you're using, I can suggest one small change that might help you maintain a consistent frequency:

Where you update previousMillis, update it to the time the next event should have occurred, not the time when your sketch dealt with it. This avoids the times slipping by whatever latency there is in your sketch. For example:

currentMillis = millis();

// sensorVal calculation ...

interval = abs(sensorVal)+1;
if( currentMillis - previousMillis > interval)
{
    previousMillis += interval;
    ...

Rather than:

    previousMillis = currentMillis;

Thank you so much :slight_smile:

Unfortunately, it don't work, the frequency still slips like 5 times per second, I've made a video of this .

I've modified my previous message, I now use micros() and i multiply sensorVal by 1000

It's perfect, I haven't got any frequency slip. But there's now a problem of precision.

IMG_0156[1].MOV (3.69 MB)

I couldn't understand what that video was showing me, I'm afraid.

Is it showing the pulse width changing, or the overall frequency changing, or what? To see the effect I was intending to cure you would need to record a pulse train. Hopefully the pulse train would keep the intended frequency even if the start/end of individual pulses may be delayed by up to a millisecond on occasion.

Given that you have solved the problem by changing to micros I suppose that is no longer relevant.

What is the precision problem?

Sorry i forgot to mention that it was the frequency shift , not the pulse with which was constant.

Here is the new code with micros() instead of milis() that gives a better precision :

float sensorVal       = 0;    // store the value coming from the sensor
int sensorPin = A0;    // select the input pin for the potentiometer
int ledPin = 7;      // select the pin for the LED
int ledState = LOW;             // ledState used to set the LED
float previousMillis = 0;        // will store last time LED was updated
int deadzone = 20; // number of the deadzone

void setup() {
  // declare the ledPin as an OUTPUT
  pinMode(ledPin, OUTPUT); //  
  
}

void loop() 
{
  
  // read the value from the sensor:
  sensorVal = analogRead(sensorPin);  // Reading the joystick
  sensorVal = map(sensorVal, 0, 1023, -512, 512); // setting the "0"
  // Generating a Deadzone
   if(sensorVal < -deadzone || sensorVal > deadzone){ // Turn only if you are not on the deadzone
     
  sensorVal = 2000000/ ( (abs(sensorVal)-deadzone) ); // F=1/t  with a multiplier to reduce the max freq, and adjusted to match the deadzone
  
  
 // Generating the temporary clock for the future stepper library 
  float currentMillis = micros();
  if(currentMillis - previousMillis > sensorVal) // Abs() gives me the absolute speed  
    {
      previousMillis = currentMillis;   
        
      if (ledState == LOW) 
        ledState = HIGH;
      else
        ledState = LOW;
      digitalWrite(ledPin, ledState);  //End of the clock                
    }
    }
}

I've added a LARGE deadzone for testing purpose.

Now it runs fine.

By precision i mean that when my pot is going at like 80% of its value, the frequency rises by "large" amounts, unlike with smaller frequencies.

I'll do some measures tomorrow, it's a bit late now !

I have to code for the stepper too, but it depends of wich component i'll use to drive my motors. My teacher showed me a IC that makes all the sequence by itself, and provides current regulation etc etc :
http://docs-europe.electrocomponents.com/webdocs/0e7f/0900766b80e7f358.pdf
It's only for bipolar. but gives me free pins for maybe a LCD upgrade.

I have to see my friend to choose what kind of steppers we'll use.

By the way, here is an idea in case i can't use them :

// idea, not real coding :


if direction == 1 : state++
if direction == 0 : state--

if state == 0 {state = 8}
if state == 9 {state = 0}

switch (state) // stepper sequence
case 1 :
case 2 :
case 3 :
case 4 :
case 5 :
case 6 :
case 7 :
case 8 :

Thanks, Pierre :slight_smile: