You have like 14 Servos hooked up to yours, right? I have one servo per board and the most I've seen someone run is 3. So, except for your setup, not sure that is going to be a problem for most. I'm just curious but what do you have 14 servos controlling? I've been trying to figure it out and for the life of me, I can't guess.
[Release] HubDuino v1.1.3 - Hubitat to Arduino / ESP8266 / ESP32 / ThingShield Integration (ST_Anything)
Just running 2 servos on the bench. Need to get this reliable before scaling up.
Oh...ok. But in general, why would you need 14 servos on one board?
Wire is cheaper than multiple boards, power supplies and enclosures. With all the dampers accessable in my basement, running wire is easy.
Even so, I might use more than one board if I find the servo processing task does not work with a large number of servos.
I’m also thinking about a dual micro contoller solution with one being the Hubduino communication interface and the second one tied to the first via serial link. The servo move routines could be placed on this second micro which would have all the servos attached to it. I think it would be fairly easy to segregate serial communication tasks from servo control via a single interrupt.
First task is to sort out what is causing my network dropout while running one or two servos. Might be as simple as inadequate power supply. I’m going to segregate micro power from servo power plus try different micro controllers.
PS I just saw your question about what the 14 servos are controlling. This is for zone control of my HVAC system duct mounted dampers.
Ah...ok. That make sense.
I am building controllable registers with servos. Two nights ago it was working great, last night it was rebooting Everytime I commanded the servo. Turns out it was my USB cable. After pulling my hair out for an hour my wife said, "yeah something's wrong with that cable, it can't charge the tablet with it" ...
I changed the cable and Bam it was working again.
Servos are very delicate when it comes to power. I have to use a 2A wall wart for them too.
So a different day, a different result. I had my servo test hardware powered down for about 30 hours and then fired it back up. Everything worked great with no changes from the setup that was driving me nuts with the Arduino frequently re-initializing its Ethernet connection. I think I had been testing the system so hard that the on board voltage regulator was getting too hot. To prevent this from happening again, I have separated the servo power supply from the micro power supply. I will test over the next day without powering down and report results. The code I am currently running is uploaded on my GitHub repository.
Your code is looking pretty nice! I have been pondering how to remove the delay() statements in order to prevent blocking calls. It would also allow multiple servos to move simultaneously, I believe. More come as I experiment with some ideas.
Dan, Thanks for reviewing my code and pondering a way to remove the need for delay().
I have been testing 3 servos on a mega with duration set to 10 seconds. All 3 child devices are connected to a single virtual switch by a rule so I can easily send simultaneous move requests. The servos move sequentially over a period of 30 seconds. The only way I can get it to fail is if I send the next on/off event more than about 15 seconds ahead of completion of the previous command. That doesn't cause a lockup, but the early event gets lost, causing states to not match actual conditions. I have to toggle on/off again to get states back in synch. There are no issues if I avoid sending commands too quickly.
I did notice an issue with one of the servos not responding after about 24 hours of being online with on/off commands being sent periodically. Every time I attempted to move that servo, the mega would reset the ethernet connection (as seen in serial monitor). The other 2 servos remained functional. Resetting the mega had no effect on the issue.
Closing browser windows that were pointed to the child devices resolved the issue. I do not understand why that fixed it, but it is not something I expect to encounter in normal use.
I'm trying another endurance run with only the virtual switch device open for sending on/off commands.
I have gone through your code and I have it up and running. So far, so good.
As understand it more and more, I am wondering about whether we want to offer the users a 'duration' or a 'rate' for making the servo move. They are two unique things and I can somewhat see value in each of them. For simplicity's sake, I would like to settle on one or the other. It appears that your code essentially is trying to do a little of both. Hence, the fudge factor I found in it.
If we are trying to replicate the current dimming functionality of Hubitat (i.e. where you can specify the time over which the current change in dim level must take), we will end up with variable servo speeds, unless the user adjust the dim duration field for each move.
We could also go for a servo 'rate' instead of duration. Something in the form of servo angle degrees/millisecond. This would allow a constant rotational rate, whether one asks for a full 180 degree change in position, or a 2 degrees change in position. I believe this is the current intent of your design, however I am not sure that the Arduino code implements this in a bullet-proof manner.
I would love to hear your opinions as you've done the most work to date. I really like these enhancements and I will work on making the motor moves asynchronous to hopefully permit multiple servos to be moving at the same time, in a smooth manner.
One more thing - I believe that some users will still want full speed control. Therefore, I am modifying the code to use milliseconds instead of seconds. I also want to permit a 'duration' of zero (i.e. full speed!).
Great to see all this work on the servo library. Glad someone was finally able to peak your interest. hehe
But yes, I agree with you. Full speed should definitely still be an option. That is the only thing that gets some of my blinds to close all the way. one set is 8' of 2" faux wood blinds and even with a full metal 7v servo it really has to crank to close them all the way.
I agree servo rate is more important than elapsed time of a given move.
I also agree going to milliseconds with 0 as the low end is the most flexible for users.
The code as it sits was partly driven by the code I started with. I was hesitant to drop the term duration input in the device driver given its history, but the current code converts this to implement a fixed rate no matter the magnitude of the move.
The full seconds and 1 second lower limit was a result of focus on my application, plus the duration parameter input from original driver code was in whole seconds.
I happy to see both of you, Ryan and Dan, aligned to diverge further from the dimming model that was the origin of the servo code. Thanks for helping me make this a more intuitive and universally usable implementation. That was my goal from the start.
I think we are discovering the secrets to motivating Dan to work on a difficult coding challenge that has no application in his own home environment.
evidence that the effort invested will benefit more than one user. I count at least 4 users making servo update requests now.
clearly stated goals for the changes.
strong enough interest from the requesters that they try to do it on their own and make progress consistent with perceived capability. At least 2 of us have contributed some steps in the right direction.
I'm wondering if we might have also sparked an idea in Dan for how he can personally use this. I hope so, because he certainly gives a lot to the community.
Motivation can be a challenge for sure. I think your list is pretty much spot on!
I have made some pretty good progress today on this. I think I have everything working the way it makes most sense. I did quite a bit of re-architecting to make it work asynchronously. Quite a few files in the main ST_Anything library had to be modified. Hopefully I didn't break anything else!
I also took the liberty to rename quite a few variables to make the code more readable (at least to me!)
I believe I have also have made it 100% backwards compatible with earlier versions of the EX_Servo class so other users will not have to make changes to their sketches if they choose to upgrade their copy of ST_Anything Arduino files. Of course, they will need to upgrade their Child Servo Groovy code now that the 'value' passed back and forth is overloaded with 2 to 3 pieces of data. (Note: This is exactly how I would have handled it as well. Nice work, Jeff!)
I'll try to get my GitHub repository updated a little later this evening so you can give it a test drive.
I have uploaded all of the code to my ST_Anything Github Repo. I still need to update the ReadMe and I will probably create a new Release as the changes are somewhat significant and useful.
In addition to the updated Child Servo groovy driver, you'll need to grab the following files as well (or you can just grab it all again if you want.)
In order to maintain backwards compatibility for existing users' sketches, I had to restore the original constructor's arguments. This means that the initial angle of the servo is back to being in 0-180 degrees instead of 0-100 percent. Also, the detachServoTime argument is back as it was before. Since the new "rate" is transmitted from the groovy driver, it really is not necessary in the sketch. I did default the rate to 2000 ms/180 degrees. This tries to prevent the servo from jumping too quickly when the microcontroller is powered on. If you need to change that value, is is yet another optional argument of the constructor. The real challenge with the initial startup is the fact that there is no way of knowing what the current position of the servo is. I decided to assume the midpoint between the minLevelAngle and maxLevelAngle. Take a look at the constructor and let me know if you have any better ideas, please.
Here is the 'documentation' for the EX_Servo class as it stands now.
// Summary: EX_Servo is a class which implements the SmartThings/Hubitat "Switch Level" device capability. // It inherits from the st::Executor class. // // Create an instance of this class in your sketch's global variable section // For Example: st::EX_Servo executor1(F("servo1"), PIN_SERVO, 90, true, 1000, 0, 180, 2000); // // st::EX_Servo() constructor requires the following arguments // - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name // - byte pin_pwm - REQUIRED - the Arduino Pin to be used as a pwm output // - int startingAngle - OPTIONAL - the value desired for the initial angle of the servo motor (0 to 180, defaults to 90) // - bool detachAfterMove - OPTIONAL - determines if servo motor is powered down after move (defaults to false) // - int servoDetachTime - OPTIONAL - determines how long after the servo is moved that the servo is powered down if detachAfterMove is true (defaults to 1000ms) // - int minLevelAngle - OPTIONAL - servo angle in degrees to map to level 0 (defaults to 0 degrees) // - int maxLevelAngle - OPTIONAL - servo angle in degrees to map to level 100 (defaults to 180 degrees) // - int servoRate - OPTIONAL - initial servo rate in ms/degree (defaults to 2000, used to ensure a gentle move during startup, afterwards comes from SmartThings/Hubitat with each move request)
I am going to wait to hear back from you to let me know how your testing goes. After we get it working I will create a new ST_Anything/HubDuino Release and will update the ReadMe files.
@kilowatts - please check out the post immediately above this one. I would love to see another video of your blinds all moving simultaneously (instead of sequentially) using the new version. You can also adjust the rate that the servos move.
Dan, I have the update running and see no initial issues. I will exercise it and study the code before sending feedback. Thank you so much!
Wow, awesome stuff happening here. As soon as I get a chance I'll do some testing on a spare nodeMCU here, although I am leaving the country for a couple weeks so it may be a while.
Dan I will also try to get this running as I am creating controllable heat registers.