Solution advice - Servo/Pixel application

Application: I have in mind a Nano Classic application which needs a single Neopixel string output(up to 32 pixels, any output pin) and up to 16 servo outputs.
The servos will be used for model railroad turnouts, and the following features would be ideal:

  • attach/detach individually
  • position setting by angle or pulse width
  • movement speed adjustable
    Pixels will be set to one of four or five colors (Red/Green/Yellow/Blue/Dark)
    I have a cobbled revision to Servo.h that allows an output pixel burst at the end of the Servo update cycle. As long as the Servo updates plus that pixel burst don't run too much over the 20 ms cycle time for the servos, it works(can be done simply by keeping the servo positions in the small angle range). But, it's inelegant, a maintenance headache, and certainly not something I'd share; and no, I won't post it, this is a request for better things to look at.

Of course, I went that way because the common pixel libraries and Servo.h don't play nice, everyone messes with the same timer, a Nano necessity.

Is there a library out there that handles both in a unified manner? Or,
A servo library that plays nice with FastLED.h or Neopixel.h?
Just looking for ideas to look at, at this point.
For example, should I look at MobaLEDLib? I've browsed it, but I don't see that it can do what I'm describing.
Thanks in advance for any pointers.

My goto solution for situations like these is to use a second microcontroller and call it a day.

After you finish the servo update for example, just set a pin HIGH on that Arduino and continuously poll a pin in another Arduino looking for the change and do your Neopixel stuff there.

My most elaborate Hallowe'en chest, for example, uses five Arduinos (edit, maybe four): One to look for IR/RFID inputs and direct traffic (Mega); one to drive the linear actuator (come to think of it I think the relay board is connected to the Mega); one to handle the audio corresponding to the IR/RFID input signals (Uno R3 and Wave Shield); one for the "breathing" 12V red trailer light (Nano Every) and one to wait for chars in Serial that correspond to Serially printed story/lore on a monitor (Nano Every). Works as expected, every time. Plus, if something were to fail, I'd have a very easy time narrowing down the issue to one Arduino's code.

That's why I like buying Nano Everys in six packs. Great for single purpose stuff like the breathing light.

1 Like

Well, with an Every you also have extra timers; that would be another approach, I guess, provided the FastLED and Servo libraries are capable of sensing what resources are already in use. Might have to dig into the libraries to try to identify that, I guess; the Every/4809 features don't seem to be prominent in either library's header file, so I'm not hopeful.

With multiple timer interrupts(servo and pixel) running async, one or the other is going to delay the alternate. Pixel update for 32 LEDs is at most 1.3 ms (1.25us * 8 *4 * 32), and obviously, servo updates are shorter, so I doubt it'd be a problem. Then, of course, there's incoming serial updates at 115200; the pixel update could cause a problem there, but it should be very rare, because the pixel transmission is only triggered by calls to show(), which would only be triggered by user actions.

Anyway, thanks for the food for thought.

1 Like

Servos without a library.

WS2812 with a home-made library.

1 Like

@xfpd
I've got far more in mind than programming 2 identical servo positions. Scaling up to 16, with unique endstops and position monitoring, etc. is already written.
My ServoPixel library runs up to 16 servos on one timer. As long as I keep the angles small(0-60, quite usable for HO turnout throwing), there's still time at the end of the servo update to put out the 1.3 ms 32-pixel colour setting, especially since it only happens when show() is called, which only happens when the user does something.

As for the 1.3 ms pixel drive, as I've said, I've got it working. Wrote my own small snippet, runs at the end of the servo update. Yes, interrupts are disabled for the necessary time, so Serial could possibly lose a char or two.

My gut feel is, it can be done with some combo of available libraries, which is why I've asked. Otherwise, my ServoPixel.h with underlying .cpp file will suffice. I'll probably have to put it up in Github, for sharing with others; I've had enough poorly documented garbage from there, though, so if I put it up, I'll try to do a better job than that; that means explanations, maintenance, etc. Also means it'll be limited to the processor I choose, which isn't as broadly useful as pointing at a couple of libraries others have toiled mightily on.
Thanks.

Thanks, but the information for all 16 servos, 32 pixels, etc. is managed within one array of structs. Assigning LED updates elsewhere would require 1 or 2 pins for communication.
And, the Nano is loafing as it is. The problem is one of resource management, not farming out subtasks, in my mind. The issue is, to accomplish what needs to happen with Servos and Pixels, that 16 bit timer is serving two masters, and the available libraries don't seem to be designed for that. Small wonder, I guess, but it's frustrating.
Anyway, I've decided that I'm simply going to forge ahead, finishing off what I've done so I can move on to other projects.
Thank you both, @hallowed31 and @xfpd, for at least attempting to assist; it's a pretty 'niche' question.
Marking this 'solved'.
C

I understand that you would like to use just a Nano and did not ask for a solution with additional hardware.

I'm with @hallowed31 but would use something like Adafruit 16-Channel 12-bit PWM/Servo Driver - I2C interface [PCA9685] : ID 815 : Adafruit Industries, Unique & fun DIY electronics and kits.

There is also an Adafruit article (Adafruit 16-Channel 12-bit PWM/Servo Driver - I2C interface [PCA9685] : ID 815 : Adafruit Industries, Unique & fun DIY electronics and kits) but it limits the number of servos.

have your tried this library

?

Thanks. It's interesting. Every 128 us the timer interrupt kicks, and a new countdown value is loaded. So, a bit more processing intensive than the T1 (16 bit) running in Servo.h.
But, could be done. But, when I think about it a bit, it gets the juices flowing - Leave T1 for Servo, but use T2 for a much-abbreviated version of the LED routine. That would actually be better for my use case.
Thanks! More stuff to chew on. If it works out that way, I'll move the solution to your reply, as the nearest good idea.
C

Further reflection, while designing hardware, has me leaving the pixel update as a conditional action at the end of the servo update interrupt. Why? Because to make it independent results in async pixel updates DURING servo updates, which is very undesirable. Better to leave it as a constrained event that only happens when show() has been called. It will happen within 20 ms of show being called, so it's not appreciably delayed; any user action that will result in an LED change propagates to the LEDs within 20 ms (+actual pixel update duration).

So, the only remaining issue is that no matter what, a pixel update can result in missed characters at the desired 115200 baud rate, as we're deaf for between 1 and 2 ms. Dropping to 4800 or 2400 baud would cure that, but that's not an option.

Have to think about that, as the source of that serial stream is async, controlled elsewhere. It may be possible to at least have an internal flag that is raised during serial activity, holding off the pixel update if a serial receive is in progress. TBD.

How much control do you have over the sender? You can send a acharacter at a time and wait for an echo before sending the next one.

Or send the first character, wait for the echo, stop the normal work and wait for the rest of the data.