Blaster Servo Help

If I were to use a servo in a blaster config, how could I get a style to respond to the reload (aux) button (EFFECT_RELOAD?) like it was a blade on/off (InOutTrL), so that it just flips back and forth between the two values… like an up/down position? Think the barrel flip of Cassian’s MW-20 from the Andor series (because that’s exactly what it is).

Additionally, how could I setup my preset to have one blade be working (responding to the fire button) in the up position, and when the servo flips, another blade is working?

I have a temporary config setup, but it isn’t nearly close to working as explained. I should also mention it is a continuous servo, so I’ll need a test config to play with the values to get a back and forth motion. I’ve assumed Rgb<20,20,20> and Rgb<128,128,128> instead of the example mentioned above.

Forgive me if this should be a new thread.

#include "proffieboard_v3_config.h"
#define NUM_BLADES 5
#define NUM_BUTTONS 2
#define VOLUME 2500
const unsigned int maxLedsPerStrip = 144;
#define CLASH_THRESHOLD_G 2.0
#define ENABLE_AUDIO
#define ENABLE_WS2811
#define ENABLE_SD
#define SAVE_STATE
#define DISABLE_DIAGNOSTIC_COMMANDS
#define DISABLE_BASIC_PARSER_STYLES
#define NO_REPEAT_RANDOM
#define DELAYED_OFF
#define ORIENTATION ORIENTATION_USB_TOWARDS_BLADE
#define BLASTER_ENABLE_AUTO
#define BLASTER_SHOTS_UNTIL_EMPTY 30  // Adjust the number based on your preference
#define BLASTER_JAM_PERCENTAGE 0 // Adjust 0-100% based on your preference
#endif

#ifdef CONFIG_PROP
#include "../props/blaster_BC_buttons.h"
#endif

#ifdef CONFIG_PRESETS
Preset presets[] = {
	{ "A180;common", "common/tracks/A180.wav",
		//Muzzle
		StylePtr<Layers<
		  Black,
		  TransitionEffectL<TrConcat<TrDelay<100>,White,TrFade<200>,Red,TrFade<300>>,EFFECT_FIRE>,
		  TransitionEffectL<TrConcat<TrDelay<100>,DeepSkyBlue,TrFade<200>,Blinking<Black,Blue,100,500>,TrFade<300>>,EFFECT_STUN>,
		  LockupTrL<Layers<
		    TransitionLoopL<TrConcat<TrInstant,White,TrFade<50>,Red,TrFade<150>>>>,TrInstant,TrConcat<TrInstant,Rgb<50,0,0>,TrFade<400>>,SaberBase::LOCKUP_AUTOFIRE>>>(),

		//Upper Barrel
		StylePtr<Layers<
		  Black,
		  TransitionEffectL<TrConcat<TrWipe<100>,White,TrWipe<100>,Red,TrWipe<200>>,EFFECT_FIRE>,
		  TransitionEffectL<TrConcat<TrWipe<100>,DeepSkyBlue,TrWipe<100>,Blinking<Black,Blue,100,500>,TrWipe<200>>,EFFECT_STUN>,
		  LockupTrL<Layers<
		    TransitionLoopL<TrConcat<TrWipe<50>,Red,TrWipe<100>>>,
		    TransitionLoopL<TrConcat<TrInstant,AlphaL<White,Bump<Int<0>,Int<25000>>>,TrFade<150>>>,
		    TransitionLoopL<TrConcat<TrInstant,AlphaL<White,Bump<Int<0>,Int<25000>>>,TrFade<150>>>>,TrConcat<TrInstant,Rgb<255,100,100>,TrFade<150>>,TrJoin<TrConcat<TrInstant,AlphaL<Rgb<50,0,0>,Bump<Int<32768>,Int<60000>>>,TrFade<400>>,TrWipeX<Int<400>>,TrWaveX<Rgb<50,0,0>,Int<1800>,Int<40>,Int<400>,Int<5000>>>,SaberBase::LOCKUP_AUTOFIRE>>>(),

		//Lower Barrel
		StylePtr<Layers<
		  Black,
		  TransitionEffectL<TrConcat<TrWipe<100>,White,TrWipe<100>,Red,TrWipe<200>>,EFFECT_FIRE>,
		  TransitionEffectL<TrConcat<TrWipe<100>,DeepSkyBlue,TrWipe<100>,Blinking<Black,Blue,100,500>,TrWipe<200>>,EFFECT_STUN>,
		  LockupTrL<Layers<
		    TransitionLoopL<TrConcat<TrWipe<50>,Red,TrWipe<100>>>,
		    TransitionLoopL<TrConcat<TrInstant,AlphaL<White,Bump<Int<0>,Int<25000>>>,TrFade<150>>>,
		    TransitionLoopL<TrConcat<TrInstant,AlphaL<White,Bump<Int<0>,Int<25000>>>,TrFade<150>>>>,TrConcat<TrInstant,Rgb<255,100,100>,TrFade<150>>,TrJoin<TrConcat<TrInstant,AlphaL<Rgb<50,0,0>,Bump<Int<32768>,Int<60000>>>,TrFade<400>>,TrWipeX<Int<400>>,TrWaveX<Rgb<50,0,0>,Int<1800>,Int<40>,Int<400>,Int<5000>>>,SaberBase::LOCKUP_AUTOFIRE>>>(),

		//Rumble Moter
		StylePtr<Layers<
		  Black,
		  TransitionEffectL<TrConcat<TrDelay<100>,White,TrFade<200>,Red,TrFade<300>>,EFFECT_FIRE>,
		  TransitionEffectL<TrConcat<TrDelay<100>,White,TrFade<200>,Blinking<Black,Red,100,500>,TrFade<300>>,EFFECT_STUN>,
		  LockupTrL<Layers<
		    TransitionLoopL<TrConcat<TrInstant,White,TrFade<50>,Red,TrFade<150>>>>,TrInstant,TrConcat<TrInstant,Rgb<50,0,0>,TrFade<400>>,SaberBase::LOCKUP_AUTOFIRE>>>(),

		//Servo
		StylePtr<Layers<Black, TransitionEffectL<TrConcat<TrInstant,Rgb<128,128,128>,TrFade<150>>,EFFECT_RELOAD>>>(),
	"preset_name" },

	/* PRESET TEMPLATE
	{ "FONT;common", "common/tracks/TRACK.wav",
		//Muzzle

		//Upper Barrel

		//Lower Barrel

		//Rumble Moter

		//Servo
		StylePtr<Layers<Rgb<128, 128, 128>, InOutTrL<TrInstant, TrInstant, Rgb<20, 20, 20>>>>(),
	"preset_name" },
	*/
},

};
BladeConfig blades[] = {
{ 0, 
	WS281XBladePtr<1, bladePin, Color8::GRB, PowerPINS<bladePowerPin2, bladePowerPin3> >(), /* muzzle */

	WS281XBladePtr<20, blade2Pin, Color8::GRB, PowerPINS<bladePowerPin4> >(), /* upper barrel */

	WS281XBladePtr<20, blade3Pin, Color8::GRB, PowerPINS<bladePowerPin5> >(), /* lower barrel */
	
	SimpleBladePtr<CH1LED,NoLED,NoLED,NoLED,bladePowerPin1,-1,-1,-1>(), /* rumble motor */
	ServoBladePtr<blade7Pin>(), /* servo, duh (free3)*/
CONFIGARRAY(presets) },
};

#endif

#ifdef CONFIG_BUTTONS
Button FireButton(BUTTON_FIRE, powerButtonPin, "fire");
Button ModeButton(BUTTON_MODE_SELECT, auxPin, "modeselect");

type or paste code here

EDIT: It looks like the servo might be this simple, but my question would remain about how to do something similar with the preset styles. I may do some digging to use a similar effect sequence as a layer wrapper.

StylePtr<EffectSequence<EFFECT_RELOAD,Rgb<20,20,20>,Rgb<128,128,128>>>(),
type or paste code here

No worries, I made it a new thread.

1 Like

Maybe like this: (used as a layer)

   EffectSequence<EFFECT_RELOAD, Black, Alpha<Black, Int<0>>>,

And then on the other blade you switch the black and transparent around.

1 Like

But don’t the other TranistionEffectLayers work on top of that? So, in a blaster setting, they’d always show up over the AlphaLayer?

EDIT: Nevermind, I just needed it as the top layer, like this:

Layers<
  TransitionEffectL<TrConcat<TrWipe<100>,White,TrWipe<100>,Red,TrWipe<200>>,EFFECT_FIRE>,
  TransitionEffectL<TrConcat<TrWipe<100>,DeepSkyBlue,TrWipe<100>,Blinking<Black,Blue,100,500>,TrWipe<200>>,EFFECT_STUN>,
  LockupTrL<Layers<
    TransitionLoopL<TrConcat<TrWipe<50>,Red,TrWipe<100>>>,
    TransitionLoopL<TrConcat<TrInstant,AlphaL<White,Bump<Int<0>,Int<25000>>>,TrFade<150>>>,
    TransitionLoopL<TrConcat<TrInstant,AlphaL<White,Bump<Int<0>,Int<25000>>>,TrFade<150>>>>,TrConcat<TrInstant,Rgb<255,100,100>,TrFade<150>>,TrJoin<TrConcat<TrInstant,AlphaL<Rgb<50,0,0>,Bump<Int<32768>,Int<60000>>>,TrFade<400>>,TrWipeX<Int<400>>,TrWaveX<Rgb<50,0,0>,Int<1800>,Int<40>,Int<400>,Int<5000>>>,SaberBase::LOCKUP_AUTOFIRE>,
  EffectSequence<EFFECT_RELOAD,Black,AlphaL<Black,Int<0>>>>
1 Like

@profezzorn I need some help understanding how the proffie is sending PWM to the servo. Firstly, this is my first attempt running servos, so I’m not entirely sure what I’ve gotten myself into. I’ve tried updating my style code with different effects, transitions, and RGB values to try to achieve what I need, but I can’t seem to get there. This is an FS90R continuous servo. In the few examples I’ve tried, it still seems to just want to run like a motor.

For context, the example style above
StylePtr<EffectSequence<EFFECT_RELOAD,Rgb<20,20,20>,Rgb<128,128,128>>>(),
had it run clockwise constantly until reload (when on the Rgb<128,128,128> setting), when it would sort of try to go counter clockwise constantly (when on the Rgb<20,20,20> side), but was jittery like the previous servo thread. I mistakenly thought that because mine was essentially a 360deg servo, half the previous example’s value would be position 180. But, I tried understanding the servo model’s requirements a little more and found the following:

Pulse Width Details:

  • Neutral/Stop: 1500 µs (or 1.5 ms).
  • Clockwise (CW) Rotation: 700 µs to 1499 µs (speed increases as pulse gets shorter).
  • Counter-Clockwise (CCW) Rotation: 1501 µs to 2300 µs (speed increases as pulse gets longer).
  • Pulse Width Range: Generally 700 µs to 2300 µs.
  • Dead Band: Around 90 µs wide, centered at 1500 µs.

So, I attempted to try understanding the CustomDriveLogic you referenced from the leds.h file to determine exactly what Rgb16 value would get me to the most accurate microsecond in my style. Then, I tried using transitions to only drive it one direction or another for a brief moment, and then hold into its center position. that ultimately ended up being this:
StylePtr<EffectSequence<EFFECT_RELOAD,TransitionEffect<Rgb16<4915,4915,4915>,Rgb16<65535,65535,65535>,TrInstant,TrDelay<500>,EFFECT_RELOAD>,TransitionEffect<Rgb16<4915,4915,4915>,Rgb16<3277,3277,3277>,TrInstant,TrDelay<500>,EFFECT_RELOAD>>>(),
My thinking being 4915 gets me approximately 1500µs for center, and the upper and lower limits are just to run it forward or backwards momentarily.

Am I on the right track? Because the only thing that managed to clean up was the jittery counterclockwise nature of my first style, however the momentary counterclockwise does happen, but It still wants to constantly run forward like a regular motor.

Filmed a quick demonstration: proffie blaster servo behavior

By default ServoPtr uses signals from 1000 us to 2000 us, that can be modified if you need the highest speed. I think Rgb16<32768,32768,32768> should be centered, Rgb<128,128,128> should also be close enough. (1501.9 us)

The math in ServoSelector::CustomDriveLogic translate one 0-65536 value (which represent a color) into another 0-65536 value (which represents 0-20 ms, which is the PWM frequency.)

Yesterday, I tried Rgb<128,128,128> as the upper limit and that value actually continuously drove the servo clockwise. So, I’m assuming I need to continue to play around with that value to find the actual stop, despite that being close to the published neutral?

If you watched the demo, any idea why the servo would only respond to every other (or so) reload transition?

I’m fairly certain that there are 360-degree servos which interpret the servo signal as absolute position instead of speed. I’m thinking that your build would benefit significantly from using such a servo.

My understanding is that such servos will go left or right based on which direction is shorter. If you try to flip it 180 degrees, it’s going to pick randomly, but you can fix that by sending an intermediate value that is only 90 degrees, and then complete the turn after it’s moved a bit.

So, I’m getting jitter at the center point, similar to the other thread. Can I adjust this to tighten the signal read so that it’s closer to the 90µs dead band? Or do I not understand that correctly?

(in other words I’ve just been playing with a simple style to find the stop value, but I’ve never had the servo fully stop moving; I’ve had it it not jitter as frequently, but RGB values I’ve returned to from previous tests do not behave the same. It’s as if there’s a dirty signal)

If you use Rgb16<32768, 32768, 32768>, then you will already be as close as is possible.

I might be wrong about this, I have not found any 360 degrees servos with absolute positioning unfortunately.

I agree that there seems to be something wrong with the signal. (Or the power to the servo) but I’m not sure why, because I don’t see it in my tests.

Okay, knowing a little more about the rgb values to get the pulses I want, I will try this other MG90S servo I have. I tried to connect it at various stages in this project and not had it move one bit. But maybe I was never in the ballpark of the signals it wanted.

I’m using this continuous motor at the recommendation of someone who did a similar project, but with a Teensy. In their tests, most 180deg servos don’t actually move fully 180, so he used this continuous servo with a physical stopper in the 3D print, relying the arduino default servo library to tell it which direction to move and for how long. It seemed to work well in that case. I’m still using the 180deg print stopper, and have been able to get this to flip-flop, but not to stay still.

I know they exist. In fact I know there’s some that can be switched between continuous and absolute positioning mode.

I’ve not followed quite closely enough to know how many revolutions are needed though, or if the servo is expected to move psuedo-continuously (e.g. multiple revolutions clockwise, only a bit counterclockwise or what have you, rather than all the way around and all the way back, to stay within the servo range).

I’m not aware of any that exist which will allow you to continuously move and have psuedo-absolute positioning. They’re all proper-absolute. E.g. you can have multiple revolutions, but you must always stay on the range.

These are almost certainly not what you’d want to buy @kersskerner, but they’re a hard example of what I’m aware of, so I’d figure I’d share anyways.

These are the “education special…” immensely overpriced, and probably too large for your application. (Though they’re at least built pretty alright, then again they better be :laughing:)

Their normal ones are 300 degrees, which also seems like it’d be enough. Again, not that you’d want to buy these, but proof that such a thing does exist. (Though, and this is what they probably are as I think more about it, depending on the room you have, I don’t fully tell from the video, you may be able to just gear up whatever random servo you have…)

Much appreciated. I’m going to see if I can run this other (simpler) 180deg servo, despite what advice was told me about how these won’t make the barrel align properly once engaged. Again, I can get the continuous one to do what I need in regards to motion. It’s the stand-still I can’t get it to do.

Here’s the latest on what it’s doing: https://www.youtube.com/watch?v=5k8uwjVcPS0

I mention in there I’ll try to connect a separate battery to power just the servo. I tried that, it didn’t respond unless negative was shared with proffie, and then it just jitters as it is wont to do.

EDIT: MG90S servo jitter, for what it’s worth both servos have been tested on OS8.4 and MasterOS versions and behave the same. Whatever the issue, it seems consistent across these two servos (and perhaps mostly related to neutral position?).

1 Like

Unfortunately, I don’t think the trim pots is going to help.
I think the generated signal is mostly fine, but then something is causing it to go nuts every now and then, and whatever is causing that is independent of the “color”.

I’m not sure what is making it go nuts though, and why doesn’t it happen for me?

I do have some ideas for things we can check or do to eliminate possible differences though:

  1. What version of arduino-proffieboard do you have? What settings do you have in Arduino->Tools ?
  2. Can you try it without an SD card, or with an empty SD card to see if that makes a difference?
  3. If you could follow the procedure here: ProffieOS Documentation: How to back up a Proffieboard and post the file here, then I can try the exact bits that you uploaded to your board, and see if they case problems on my board or not.

I agree. I’ve tried a lot tests with the other MG90S servo, and any position I ask it to be in it jitters in that position. With the FS90R servo, I was connected to battery positive, proffie neg (essentially battery neg) and Free3. I’ve connected the MG90S to 5.5v out for now, but tried battery pos, neither works without using proffie ground/neg (i mention in one of the videos using a separate battery connected only to servo but it didn’t do anything), and I’ve sinced moved to Free2. I wondered if Free3 being connected to pin 9 and 10 (one being analog) might play into the mix, but still behaves the same despite moving to Free2.

I’m currently still getting jitter at Rgb16<0,0,0> and Rgb<65535,65535,65535> (which corresponds to 45 and 135 on this servo), even though I’ve tried deviations from those rgb values just to see what happens. Basically, I can drive the servo, but I can’t escape jitter.

I would like to understand how to modify the CustomDriveLogic to go from 0.5ms to 2.5ms for this particular servo to go 0deg to 180deg, but I’m guessing I’ll still get jitter. I was seeing if ChatGPT could lend me some insight into what that section does, and which values to modify, but it assumes to much, wants me to alter too much code. Plus, I’m not a fan of it, as it’s prone to making things up. I also can’t fill in some gaps in its reasoning…so, perhaps the solution could be other hardware? Definitely don’t know why your servo works fine. I need a similarly sized servo to fit this build (22.8mmX12.2mmX28.5mm). Yours and the one mentioned by ryryog are too large (and his too complicated).

I’m using Arduino 1.8, proffieboard 4.6.0 plugin, I’ve tried OS8.4 and MasterOS

I tried both, and still jitters.

Give me a moment to attempt your number 3.

You would replace this:

      return 3277 + ret / 20; // 1 - 2 ms

with this:

   return 1638 + ret / 10; // 0.5 - 2.5 ms

This is ancient and I recommend upgrading to 2.3 or whatever is the latest, however I don’t think it will make a difference for this particular problem.