Notifications
Clear all

Unblock while loop while running a Stepperonline servo using Accelstepper or PWM until weight reached using HX711 load cell amplifier

13 Posts
4 Users
2 Likes
2,547 Views
(@jamesgi001)
Member
Joined: 1 year ago
Posts: 13
Topic starter  

I have been researching this for two days and going a bit crazy! I am trying to run my StepperOnline easy servo motor that grinds coffee until a pre-set weight has been reached. The code works fine and stops the servo though reading the weight from inside the while loop kills the speed to nearly zero. Even commenting out the serial print still does not help as the speed killer is obviously reading the load cell. I am thinking I will need to use some flags maybe?

I have to use high setMaxSpeed values (15000 = highest possible speed) on pin 4 of the Mega (980Hz) which is just fast enough using Accelstepper. I have achieved higher speeds using this servo motor with PWM on the same port though either way it grinds to a near standstill as soon as I try to read the HX711 weight value. Any suggestions how to unblock the loop would be most appreciated... thanks again in advance!

 

https://www.omc-stepperonline.com/nema-23-integrated-easy-servo-motor-90w-3000rpm-0-3nm-42-49oz-in-20-50vdc-brushless-dc-servo-motor-isv57t-090


   
Quote
Ron
 Ron
(@zander)
Father of a miniature Wookie
Joined: 3 years ago
Posts: 6888
 

@jamesgi001 I had a look at your sketch. Is there any reason why you can't take the weight reading code and do it before the decision? Obviously, it now must be an if then else rather than a while but that at least, as you say, 'unblocks' the code.

The real solution lies in the ability to speed up the 

weight = scale.get_units(1);

statement.

First computer 1959. Retired from my own computer company 2004.
Hardware - Expert in 1401, and 360, fairly knowledge in PC plus numerous MPU's and MCU's
Major Languages - Machine language, 360 Macro Assembler, Intel Assembler, PL/I and PL1, Pascal, Basic, C plus numerous job control and scripting languages.
Sure you can learn to be a programmer, it will take the same amount of time for me to learn to be a Doctor.


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

@jamesgi001

How much slop do you allow for the weight ? You're using 15g as a test but would you be happy with 14, 16, or more or less (expressed as weight or percentage of target).

Also, is the grinding process reasonably consistent ? That is, if you run it for 10 seconds you'll get (nearly) the same amount as any other time you ran it for 10 seconds.

It's possible to improve the grinding elapsed time if either (or better still, both) of those are true.

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


   
Ron reacted
ReplyQuote
(@jamesgi001)
Member
Joined: 1 year ago
Posts: 13
Topic starter  

Thanks @Ron - I havent tried a if, then else loop yet - could be worth a shot... I will try this and see if it works. 

I am also thinking whatever I do, it is really going to require a seperate parallel running loop checking weight - like  a rasberry PI can do that is not possible on an arduino unless maybe using a flag? I.e. start the grinding, let it run in the background while checking the weight and then stop the loop with a flag or interrupt?   Otherwise, I may need to set up a separate arduino connnected by serial that has the sole task of checking weight and then send a flag to the main Mega controller?

Thanks for the suggestion as well @Will, actually, discerning coffee drinkers are looking at 0.5 grams as the accuracy required for their 'reciepe'. I am creating what's known as a 'single dose, zero retention' grinder where if you put say 17g oif beans in, you get next to 17g of grounds out... and this is one of the first thing my product will be judged upon. Also, different coffee brands and styles grind in very different ways depending on oil and moisture content. I already have a different fuction that is to 'grind by time' included in this product's functions, though, if people want to use the 'grind by weight' function, it needs to be spot-on with regards accuracy.

Thanks to you both for your valuable input and suggestions!


   
ReplyQuote
(@davee)
Member
Joined: 3 years ago
Posts: 1653
 

Hi @jamesgi001,

  Changing the order in which things are done, etc to untangle the print hold ups is obviously a priority, but sometimes it is useful to have a guide to progress of a process as it happens.

Serial.print is meant for debugging, and is typically much slower than the processor's 'number crunching' capability, but can be helpful in 'explaining' what is happening, providing it does not get in the way. Hence, consider ways of minimising Serial.print's footprint.

--

Increase baud rate parameter in Serial.begin(115200) ... look on the serial monitor control to see the list of values it supports. Then do a few simple experiments to find the fastest one that works without losing characters. (Create a tiny separate sketch for this test, to avoid unnecessary bean crunching, then transfer your conclusion back into the main sketch.)

-------

Minimise the number of characters that need to be sent, and print along the line ... typically a simple logic or arithmetic line of code takes less time than printing a single character, so show progression (e.g. weight increase by 0.2 g) by printing just a single character, with all characters on the same line. You can consider using different characters to make them easy to count ... e.g. a '-' for each 0.2g, unless it is an integer '1, 2, 3 etc., in which case print a '+'.

So 2.4g would look like ----+----+--  

Of course, feel free to adapt the basic principle for the best result. Again, trial with a separate sketch first.

---------------

Try to avoid/minimise printing newlines.

-------------

Then at the end of a grind, outside of the 'grinding' loop, you can print a precise finishing weight, as a measure of the overall process, with as much embellishment, statistics, etc. as you wish, as the grinder will have stopped. This might mean saving results in an array, during the grind, and then analysing them at the end.

-------

The above hints are based on 'gut feeling and experience' ... for a more detailed approach you need to find out the timing of the parts of your program, so that you can accurately target the bottlenecks, but this could be a major discussion it its own right. Humans, myself included, are notoriously bad at judging where the bottlenecks are in more complex programs, so park this as a thought for the future.

-------

Best wishes and good luck,

Dave


   
Ron reacted
ReplyQuote
Ron
 Ron
(@zander)
Father of a miniature Wookie
Joined: 3 years ago
Posts: 6888
 

@jamesgi001 Check out cooperative multi-tasking, Mr. Bacon has a video, and I am sure there are others. The best, of course, would be pre-emptive multitasking or SMP (symmetric multiprocessing). RTOS is also an obvious choice, but I just found a new player. Check out LINK

My apologies for bringing my main frame mindset to the micro world, but I think the concepts used in the big boys were designed to solve similar problems. My all-time favourite computer was the Stratus with 6 logical CPU's 24 physical as it was a pair and spare designed for fault tolerance. There is no such thing as throttling or replay of stock market ticker data; either catch it or lose it, so we needed a way to design scheduling algorithms that guarantee no data loss. BTW, the CPU was a detuned  (8mHz?) Motorola 68000 

First computer 1959. Retired from my own computer company 2004.
Hardware - Expert in 1401, and 360, fairly knowledge in PC plus numerous MPU's and MCU's
Major Languages - Machine language, 360 Macro Assembler, Intel Assembler, PL/I and PL1, Pascal, Basic, C plus numerous job control and scripting languages.
Sure you can learn to be a programmer, it will take the same amount of time for me to learn to be a Doctor.


   
ReplyQuote
(@jamesgi001)
Member
Joined: 1 year ago
Posts: 13
Topic starter  

All super interesting ideas. I tried slimming down everything (thanks @DaveE!) and got no appreciable performance gains... seems like plenty of other people are talking about this issue including discussions about multi-tasking bootloaders for Arduino. (Interesting your background @Ron - you must have seen some crazy developments over time... I often think about that wonderful movie 'Hidden Figures' when talking early mainframes. Good ol' 60's & 70's & NASA!)

I have two things I need to monitor, one is weight and the other amps from the the main servo. I think that the only way this will work as a quick fix will be to install two nanos or similar reading the outputs of each function and then send the data back to the main Mega controller via serial. The main loop therefor wont need to read anything - just check the data condition up front. I found these... 

https://littlebirdelectronics.com.au/products/beetle-the-smallest-arduino-microcontroller

so will give this a try and let y'all know what happens.

Thanks again!


   
ReplyQuote
Ron
 Ron
(@zander)
Father of a miniature Wookie
Joined: 3 years ago
Posts: 6888
 

@jamesgi001 The tasking solution I mentioned is the logical equivalent and might be faster since no inter-board comms are needed. The main loop in a simple tasking program is a single line of code, but it can be more. Check the examples (the library is TaskScheduler with 31 examples) before you jump to conclusions. You can even configure each task to have different priority schemes, like weight and amps. Remember, if you go with the 3-board solution, the main board has the same problem you have now, and I would propose the same solution. If you want to get super fancy, move to a 4 CPU board, put weight on 1, amps on another, supervisory on a 3rd and the 4th is for everything else at lowest priority. Reminds me of my old days! Sounds like fun.

First computer 1959. Retired from my own computer company 2004.
Hardware - Expert in 1401, and 360, fairly knowledge in PC plus numerous MPU's and MCU's
Major Languages - Machine language, 360 Macro Assembler, Intel Assembler, PL/I and PL1, Pascal, Basic, C plus numerous job control and scripting languages.
Sure you can learn to be a programmer, it will take the same amount of time for me to learn to be a Doctor.


   
ReplyQuote
Ron
 Ron
(@zander)
Father of a miniature Wookie
Joined: 3 years ago
Posts: 6888
 

@jamesgi001 If you think 'performance' is the issue (I doubt it), then I don't hear you mentioning any performance tweaking like inline, unroll_loops etc. Remember, the default behaviour of the compiler is to save space to generate compact code at the expense of time. Have a look at Mr. Bacon's video called "GCC Compiler Optimisation." I don't know off the top of my head if loop variables are automatically put in registers, but to be 100% honest, I doubt the CPU is your bottleneck. You will be shocked if you ever get the chance to see a graphical representation of what a microprocessor is doing at each microsecond of time. The average application spends the majority of its time in busy wait. I had the tools to do that when I was employed as a system performance tuner, but I am unaware of anything for this device class.

Thinking back to something you might have said, if the weighing function is taking too long, then allowing the current measurement task to run while the weight measurement task is idle would be my avenue of attack. Just because the elapsed time for something is too long does NOT mean it was productively busy. In systems tuning, there is a very precise vocabulary to identify the states of processors and peripherals. When I think back to my first foray into this field, I was wrong 100% of the time. It took a while to get my mind to work like an MPU or MCU to develop the gut feeling that eventually is proven correct. Don't worry, you are still young, so the 10 or so years that takes is a piece of cake LOL.

This is an excellent example of why pre-emptive tasking is superior to cooperative tasking for systems involving I/O. When a certain large computer company discovered that their cooperative tasking was a problem, they invented stand-apart I/O controllers that ran asynchronously, thus covering up the problem most of the time.

The best system builders of the early PC days used the oft-forgotten 8089 chip since it was a stand-apart/alone IO controller. It was very rare, and their PCs were waaaaaaay faster and commanded much higher prices.

First computer 1959. Retired from my own computer company 2004.
Hardware - Expert in 1401, and 360, fairly knowledge in PC plus numerous MPU's and MCU's
Major Languages - Machine language, 360 Macro Assembler, Intel Assembler, PL/I and PL1, Pascal, Basic, C plus numerous job control and scripting languages.
Sure you can learn to be a programmer, it will take the same amount of time for me to learn to be a Doctor.


   
ReplyQuote
Ron
 Ron
(@zander)
Father of a miniature Wookie
Joined: 3 years ago
Posts: 6888
 

@jamesgi001 I just tried, and yes, for (register int loopVar = 0; etc etc is valid. I wonder how much faster register access is than memory?

First computer 1959. Retired from my own computer company 2004.
Hardware - Expert in 1401, and 360, fairly knowledge in PC plus numerous MPU's and MCU's
Major Languages - Machine language, 360 Macro Assembler, Intel Assembler, PL/I and PL1, Pascal, Basic, C plus numerous job control and scripting languages.
Sure you can learn to be a programmer, it will take the same amount of time for me to learn to be a Doctor.


   
ReplyQuote
(@jamesgi001)
Member
Joined: 1 year ago
Posts: 13
Topic starter  

Thanks @Ron for your really amazing research and ideas. sorry for slow response - first day back at work after holidays (poop emoji).

I spent all yesterday playing with serial uart comms and seems it will be possible to get slave boards to do the work though your idea is far slicker and if it works as you say (awesome that you tested it!) it's certainly worth a shot to try.

Actually the problem is not as complex as you mention. I have two different ways of grinding, one is to grind until the beans are finished (i.e. enough for one shot so pour in pre-measured 17g) and this is detected though a 5 amp hall effect sensor on the main grinder motor that draws around 4A when grinding. Once the beans are finished, it spins up higher for a few seconds to clear the burrs then stops automatically - hopefully low retention left behind.

Another, different grinding option is to grind by weight and here, more than enough beans for one shot are poured in, and then it stops after grinding, say, 17g that is measured by the load cell in a cup below the grinder exit. Hence, it doesn't need to do both amps and weight in the same loop as different functions are called for each oiption.

So, this will require even less processing in the same loop. 

Posted by: @zander

register int loopVar = 0

Is this referring to the avr-os function library?

If I can drive the motor using PWM (is possible faster than with Accelstepper on this servo) while measuring either weight or amperes simultaneously using the avr-os library then it will be the far better option. Interesting what you say about CPU/processor usage and performance.

However, luckily we have a one day public holiday here tomorrow in Australia (happy emoji) so I can get stuck into this then. I will report back the results.

I seem to remember using the Apricot 8089 computer so maybe I am not so young after all. Certain large Co = IBM?


   
ReplyQuote
(@jamesgi001)
Member
Joined: 1 year ago
Posts: 13
Topic starter  

Sorry reply should have been to @zander !


   
ReplyQuote
Ron
 Ron
(@zander)
Father of a miniature Wookie
Joined: 3 years ago
Posts: 6888
 

@jamesgi001 

Posted by: @zander

 

register int loopVar = 0

 

 

Is this referring to the avr-os function library?

 

NO, that is just regular old C. Do you have a copy of K&R? If not, MEMORIZE it as step one. The only time you need serious C++ is when creating a library, and with over 50 years of experience, I still don't know how to do that.

Now that you have given us a little bit about the requirements as in 

Hence, it doesn't need to do both amps and weight in the same loop as different functions are called for each oiption.

The problem is simple. Here is the paraphrased solution to your underlying question

void loop () {

  If (some switch or other external real world signal is TRUE) {

    perform the weight based procedure;

  } else {

    perform the amps based procedure

  }

}

 

I am a bit surprised there is not a time-based approach. All my coffee grinders have used that.

Attached is the device used to select Weight or amps. It might even be better to use a double pole double throw so it both selects and turns on the grinder, but I will leave it to you to figure out how to wire that. Following is the Amazon.CA link for the SPST switch.

Amazon link here

Certain large Co = IBM?

Sorry, I am under lifetime NDA's and security rules that prevent me from answering that.

 

 

 

 

First computer 1959. Retired from my own computer company 2004.
Hardware - Expert in 1401, and 360, fairly knowledge in PC plus numerous MPU's and MCU's
Major Languages - Machine language, 360 Macro Assembler, Intel Assembler, PL/I and PL1, Pascal, Basic, C plus numerous job control and scripting languages.
Sure you can learn to be a programmer, it will take the same amount of time for me to learn to be a Doctor.


   
ReplyQuote