Notifications
Clear all

Introduce myself and my stepping motor project (with questions)

41 Posts
5 Users
12 Likes
2,286 Views
 GNK
(@gnk)
Member
Joined: 3 years ago
Posts: 12
Topic starter  

Hi everyone,

My name is Greg Kawchuk and I'm a professor at the University of Alberta. Many times in our lab, we have a project that involves an Arduino etc, but do not have ongoing expertise to make sure it gets over the finish line (students have this habit of graduating!).  

In this case, I have a project where we want to control a stepping motor that extends a linear probe into an object and then stops when an attached load cell reaches a specific voltage level due to compression of the object. My question is about the efficiency of the coding for this task. 

One approach would be to set up a loop where the motor is given 1 step, the load cell is polled and then the loop is repeated until either the load threshold is reached or a maximum number of loop iterations are performed (which correspond to the maximal distance the probe can be extended). Say that value is 1,000 steps.

The other approach would be to request that the motor move the maximal number of steps (1,000) but then find a way to poll the load cell to interrupt the 1,000 step request if the load threshold is reached. 

I'm not sure if the second approach is possible or if it is, if it would be "better" or more "efficient" code versus an iterative loop. If it is possible, is any efficiency gained in this approach lost if you had to then set up a counter to know how many steps were executed before the code was interrupted by the load cell? 

Any suggestions? It might not matter in the end, but I'm curious about keeping the computational load on the Arduino to a minimum.

Also, I am on the lookout for chassis-mount, momentary contact buttons to swap-out for the typical breadboard buttons. Any suggested part numbers from Digi-key etc would be appreciated greatly!

Thank you in advance for any and all suggestions!

Greg


   
Quote
Will
 Will
(@will)
Member
Joined: 3 years ago
Posts: 2527
 

@gnk

It's hard to say exactly without knowing more about the responsiveness of the sensor.

At a guess, I'd suppose that the load cell takes longer to react than the stepper will need to "step". That suggests that step, sense, repeat would be the way to go.

On the other hand, if the sensor is (virtually) instantaneous then just keep doing as above but step faster 🙂

Even if you tried advancing 1000 steps at a time, you'd still have to interrupt the stepping process to have the sensor take a reading, so what would you gain ?

Perhaps I've missed something ?

Anything seems possible when you don't know what you're talking about.


   
GNK reacted
ReplyQuote
frogandtoad
(@frogandtoad)
Member
Joined: 5 years ago
Posts: 1458
 

@gnk

Posted by: @gnk

Hi everyone,

My name is Greg Kawchuk and I'm a professor at the University of Alberta. Many times in our lab, we have a project that involves an Arduino etc, but do not have ongoing expertise to make sure it gets over the finish line (students have this habit of graduating!).  

In this case, I have a project where we want to control a stepping motor that extends a linear probe into an object and then stops when an attached load cell reaches a specific voltage level due to compression of the object. My question is about the efficiency of the coding for this task. 

One approach would be to set up a loop where the motor is given 1 step, the load cell is polled and then the loop is repeated until either the load threshold is reached or a maximum number of loop iterations are performed (which correspond to the maximal distance the probe can be extended). Say that value is 1,000 steps.

The other approach would be to request that the motor move the maximal number of steps (1,000) but then find a way to poll the load cell to interrupt the 1,000 step request if the load threshold is reached. 

I'm not sure if the second approach is possible or if it is, if it would be "better" or more "efficient" code versus an iterative loop. If it is possible, is any efficiency gained in this approach lost if you had to then set up a counter to know how many steps were executed before the code was interrupted by the load cell? 

Any suggestions? It might not matter in the end, but I'm curious about keeping the computational load on the Arduino to a minimum.

Also, I am on the lookout for chassis-mount, momentary contact buttons to swap-out for the typical breadboard buttons. Any suggested part numbers from Digi-key etc would be appreciated greatly!

Thank you in advance for any and all suggestions!

Greg

Using an interrupt may be more efficient, as it is considered to be a non blocking operation, but it's something you'll have to bench test to be sure.  Which is the most important measure? i.e:- the 1000 steps or an specific load measurement?

Cheers.


   
GNK reacted
ReplyQuote
jker
 jker
(@jker)
Member
Joined: 3 years ago
Posts: 82
 
Posted by: @gnk

In this case, I have a project where we want to control a stepping motor that extends a linear probe into an object and then stops when an attached load cell reaches a specific voltage level due to compression of the object. My question is about the efficiency of the coding for this task. 

One approach would be to set up a loop where the motor is given 1 step, the load cell is polled and then the loop is repeated until either the load threshold is reached or a maximum number of loop iterations are performed (which correspond to the maximal distance the probe can be extended). Say that value is 1,000 steps.

The other approach would be to request that the motor move the maximal number of steps (1,000) but then find a way to poll the load cell to interrupt the 1,000 step request if the load threshold is reached. 

I'm not sure if the second approach is possible or if it is, if it would be "better" or more "efficient" code versus an iterative loop. If it is possible, is any efficiency gained in this approach lost if you had to then set up a counter to know how many steps were executed before the code was interrupted by the load cell? 

Any suggestions? It might not matter in the end, but I'm curious about keeping the computational load on the Arduino to a minimum.

I'm not exactly sure what the usecase is, but this doesn't sound too different from limit switches attached to an axis on a 3d printer. The trigger in this case is a sensor with analog input instead of digital on/off, but this does look very similar.

There are a few engineering questions here: How fast is the motor/load moving? This mainly affects whether you're going to need soft-stop handling on the stepper. How catastrophic is "overshoot"? A 3d printer axis relies on the fact that there is sufficient "slop" in the limit switch to allow the not-terribly-quickly-moving motor to soft-stop before crashing the bottom of the limit switch, potentially damaging something.

The question on whether the arduino is sufficient for the task depends entirely on the answers to those questions.

My usual approach for this kind of task is to use the AccelStepper library and let it handle most of these details. Set the initial speed you want in setup, setup a few constants, then your loop() basically consists of:

if (!foundTarget) {
    float sensorValue = analogRead(SENSOR_PIN);
    if (sensorValue >= DETECTION_TRIGGER) {
        motor.SetSpeed(0);
        foundTarget = true;
    } else {
        if (sensorValue + GETTING_CLOSE_THRESHOLD >= DETECTION_TRIGGER)
            motor.SetSpeed(SLOW_SPEED);
        motor.runSpeed();
    }
}

This is essentially implementing the first approach you mentioned with the accelstepper library. You can do something similar for the second approach, but getting the slowing code to work correctly may be trickier.

"A resistor makes a lightbulb and a capacitor makes an explosion when connected wrong"
"There are two types of electrical engineers, those intentionally making antennas and those accidentally doing so."


   
ReplyQuote
 GNK
(@gnk)
Member
Joined: 3 years ago
Posts: 12
Topic starter  

@jker 

Thank you for this. What you suggest is what we are doing now. Except.... The issue we are running into now is that when we extend the linear motor it does not move as quickly as we'd expect because we are simultaneously collecting the load signal. We know this because when the load limit is reached, we then retract the motor without collecting a load signal and the motor moves about 2x faster. We've improved the system greatly from ditching the HX711 load cell chip which was limited to 80Hz and are now running a 16 bit ADC at just less than 1kHz. But even then, it's still not as fast as the retraction speed. Thinking of moving to a 12 bit ADC which can run at ~ 3KHz. Or, it could be our code is not efficient. Thoughts? 


   
ReplyQuote
 GNK
(@gnk)
Member
Joined: 3 years ago
Posts: 12
Topic starter  

We are also saving the step and load data to a SD card which perhaps is a bottle neck as well. 


   
ReplyQuote
Will
 Will
(@will)
Member
Joined: 3 years ago
Posts: 2527
 

@gnk 

As long as you are doing anything extra when moving the probe forwards that you're not doing when moving it backwards means that it must retract faster than it advanced.

That includes sensing load as well as saving step and load data to an SD card.

You could improve the speed by saving the step and load data to an array in memory and then writing it all at once to the SD card afterwards. Writing to the SD card will eat a fair amount of time, but you may not have enough memory to hold the whole dataset.

Anything seems possible when you don't know what you're talking about.


   
GNK reacted
ReplyQuote
jker
 jker
(@jker)
Member
Joined: 3 years ago
Posts: 82
 

This is actually a fun thing to experiment with.

Try the following code with an arduino and an oscilloscope:

bool x = false;
void loop() {
   x = !x;
  digitalWrite(TEST_PIN, x);
}

The resulting frequency will vary a bit, but this gives me ~166kHz on my Arduino Uno. If you want to manage the stepper manually, this is your limit if you are using the digitalWrite interface.

One thing you will realize if you look at the code, however, is that the digitalWrite interface is pretty slow. Replacing that call with PORTD = (PORTD ^ B10000000); (for digital pin 7) For me, that gets up to ~500 kHz. This is effectively your arduino pulse speed limit in the normal loop() code. You can do the same basic thing with interrupts via TCNTx and the overflow registers, but I wasn't able to top 500kHz in my testing, although the timing consistency will be more reliable. YMMV

(I know people have been able to boost a simple toggle test like this well into the megahertz range, but I haven't duplicated this myself)

it does not move as quickly as we'd expect because we are simultaneously collecting the load signal

This is somewhat unlikely. There is a conversion delay in the analogRead function, but I would encourage you to use a variant of the above code to determine how much it slows things down.

EDITED: What speed do you want, anyways? (preferably in pulses/second)

Posted by: @gnk

We are also saving the step and load data to a SD card which perhaps is a bottle neck as well. 

This is highly likely. Flash writing is, at this level, extremely slow. I would definitely try cutting this out as a test first.

"A resistor makes a lightbulb and a capacitor makes an explosion when connected wrong"
"There are two types of electrical engineers, those intentionally making antennas and those accidentally doing so."


   
ReplyQuote
 GNK
(@gnk)
Member
Joined: 3 years ago
Posts: 12
Topic starter  

@jker 

Thanks for this - and the testing. Nice work! Data wins 🙂

We'll try cutting out the SD card write as a first step. But even if this solves the speed issue, we will still need to collect the step and load data. If we wrote the data to an array and then saved the array afterwards as was suggested, can you advise as to the memory limit we would have to work with? Do you see any other options? 

Greg


   
ReplyQuote
jker
 jker
(@jker)
Member
Joined: 3 years ago
Posts: 82
 
Posted by: @gnk

@jker 

Thanks for this - and the testing. Nice work! Data wins 🙂

We'll try cutting out the SD card write as a first step. But even if this solves the speed issue, we will still need to collect the step and load data. If we wrote the data to an array and then saved the array afterwards as was suggested, can you advise as to the memory limit we would have to work with? Do you see any other options? 

Greg

Memory is pretty tightly constrained on the arduino platforms. AFAIK you're limited to 2k of SRAM for all variables. ( https://www.arduino.cc/en/pmwiki.php?n=Tutorial/Memory)

I would also be somewhat suspicious of the code used to prepare the write to flash. The Arduino String code is legendarily terrible and prone to both unnecessary memory usage and performance issues.

"A resistor makes a lightbulb and a capacitor makes an explosion when connected wrong"
"There are two types of electrical engineers, those intentionally making antennas and those accidentally doing so."


   
GNK reacted
ReplyQuote
Will
 Will
(@will)
Member
Joined: 3 years ago
Posts: 2527
 
Posted by: @jker FYI @gnk

Memory is pretty tightly constrained on the arduino platforms. AFAIK you're limited to 2k of SRAM for all variables. ( https://www.arduino.cc/en/pmwiki.php?n=Tutorial/Memory)

I would also be somewhat suspicious of the code used to prepare the write to flash. The Arduino String code is legendarily terrible and prone to both unnecessary memory usage and performance issues.

It would also be much faster to store and retrieve the float data in its native float form as bytes.

Anything seems possible when you don't know what you're talking about.


   
jker and GNK reacted
ReplyQuote
jker
 jker
(@jker)
Member
Joined: 3 years ago
Posts: 82
 
Posted by: @will

It would also be much faster to store and retrieve the float data in its native float form as bytes.

This is very true, and I was trying to figure out where it came from.... then I saw it in my code snippet.

Oops! That is definitely a mistake. Avoid float if you can.

 

Unlike modern desktop processors, where floating point is often faster than integer calculations, AVR/arduino does not have dedicated floating point circuitry. This means that almost everything you do with floating point is going to be slow, including converting an ADC input to float. If you can stick with ints, it's usually best to do so.

"A resistor makes a lightbulb and a capacitor makes an explosion when connected wrong"
"There are two types of electrical engineers, those intentionally making antennas and those accidentally doing so."


   
GNK reacted
ReplyQuote
 GNK
(@gnk)
Member
Joined: 3 years ago
Posts: 12
Topic starter  

@jker @will

Any suggestions from you two on how to do this? I would be monitoring the load cell in bits not mv? 

 


   
ReplyQuote
Will
 Will
(@will)
Member
Joined: 3 years ago
Posts: 2527
 

@gnk @jker

If you're currently receiving the load data via an analog pin, then just save the 0-1023 value as an int and process it into whatever units a load cell produces when you need to display (or do some further calculation with) it.

Anything seems possible when you don't know what you're talking about.


   
jker reacted
ReplyQuote
 GNK
(@gnk)
Member
Joined: 3 years ago
Posts: 12
Topic starter  

@will 

Right now, we are reading the load cell signal with a 16-bit ADC (ADS1115) which uses I2C. We wanted better resolution than the inherent 10-bit approach. Thoughts? 


   
ReplyQuote
Page 1 / 3