0

Motor Shield V2 + Servo + Neopixels Together?
Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.

Motor Shield V2 + Servo + Neopixels Together?

by scotch1 on Sun Sep 08, 2019 3:18 am

How to make the Servo go between 0 to 180 and back to 0 with the pulsewhite dimming a 7 lcd neopixel?
Tried to bridge the issue between Neopixels and Servos with https://learn.adafruit.com/neopixels-and-servos/the-ticoservo-library

Attempted code, but nothing......

Code: Select all | TOGGLE FULL SIZE
/*------------------------------------------------------------------------
  Adafruit_TiCoServo example for ATmega-based boards such as the Arduino
  Uno, Leonardo, Mega, Duemilanove and compatible boards such as the
  Adafruit Pro Trinket, Flora or PJRC Teensy 2.0 (not Trinket or Gemma,
  see other example for that).

  THE GOOD NEWS:
  - NeoPixels and servos in the same sketch!

  THE BAD NEWS:
  - Limited to 2 servos on the most popular boards (4-12 on others).
  - Servos must be on specific pins. This is explained later in the code.
  - Supports the most common AVR-based boards, but not everything.
  - Uses up Timer/Counter 1, a popular choice of other time-critical
    libraries such as WaveHC. Can only do so much in one sketch.
    Some boards (Leonardo, Mega) have additional 16-bit timers available.

  Example reads a potentiometer on pin A0, moves a servo (pin 9) and
  fills a portion of a NeoPixel strip (pin 6) to match.

  https://learn.adafruit.com/neopixels-and-servos/the-ticoservo-library
  ------------------------------------------------------------------------*/

#if defined(__AVR_ATtiny85__)
 #error "This code is for ATmega boards, see other example for ATtiny."
#endif
#include <Adafruit_NeoPixel.h>
#include <Adafruit_TiCoServo.h>

// NeoPixel parameters. These are configurable, but the pin number must
// be different than the servo(s).
#define N_LEDS       7
#define LED_PIN       6

// Servo parameters. These have limited configurability. Compatible pins,
// for example, are determined by the specific hardware. On Arduino Uno,
// Diecimila and Adafruit Pro Trinket, pins 9 and 10 are supported by the
// library. On Arduino Leonardo: pins 5, 9, 10 and 11. Adafruit Flora:
// pins D9, D10. PJRC Teensy 2.0 (not Teensy++ or 3.X): pins 4, 9, 14, 15.
// Arduino Mega: 2, 3, 5, 6, 7, 8, 11, 12, 13, 44, 45, 46.
// Servo position can be specified in degrees or in microseconds; library
// can distinguish between the two. The #defines below are reasonable
// min/max pulse durations (in microseconds) for many servos, but for
// maximum control you'll probably need to do some calibration to find
// the optimal range for your specific servos.
#define SERVO_PIN    9
#define SERVO_MIN 1000 // 1 ms pulse
#define SERVO_MAX 2000 // 2 ms pulse

int pos = 0;    // variable to store the servo position

Adafruit_NeoPixel  strip = Adafruit_NeoPixel(N_LEDS, LED_PIN);
Adafruit_TiCoServo servo;

void setup(void) {
  servo.attach(SERVO_PIN, SERVO_MIN, SERVO_MAX);
  strip.begin();
  strip.show();            // Turn OFF all pixels ASAP
  strip.setBrightness(50); // Set BRIGHTNESS to about 1/5 (max = 255)
}

void loop(void) {
  int a, x;
  a = analogRead(0);                            // 0 to 1023
  x = map(a, 0, 1023, SERVO_MIN, SERVO_MAX);    // Scale to servo range
  //servo.write(x);                               // Move servo
  for (pos = 0; pos <= 180; pos += 1) { // goes from 0 degrees to 180 degrees
    // in steps of 1 degree
    servo.write(pos);              // tell servo to go to position in variable 'pos'
    delay(15);                       // waits 15ms for the servo to reach the position
  }
    for (pos = 180; pos >= 0; pos -= 1) { // goes from 180 degrees to 0 degrees
    servo.write(pos);              // tell servo to go to position in variable 'pos'
    delay(15);
    }

    pulseWhite(5);
 
  //x = map(a, 0, 1023, 0, strip.numPixels());    // Scale to strip length
  //strip.clear();
  //while(x--) strip.setPixelColor(x, 255, 0, 0); // Set pixels
  //strip.show();                                 // Update strip
}

void pulseWhite(uint8_t wait) {
  for(int j=0; j<256; j++) { // Ramp up from 0 to 255
    // Fill entire strip with white at gamma-corrected brightness level 'j':
    strip.fill(strip.Color(0, 0, 0, strip.gamma8(j)));
    strip.show();
    //delay(wait);
  }

  for(int j=255; j>=0; j--) { // Ramp down from 255 to 0
    strip.fill(strip.Color(0, 0, 0, strip.gamma8(j)));
    strip.show();
    //delay(wait);
  }
}

scotch1
 
Posts: 78
Joined: Mon Nov 26, 2012 12:13 am

Re: Motor Shield V2 + Servo + Neopixels Together?

by adafruit_support_bill on Sun Sep 08, 2019 7:20 am

If you want the servo movement and pulsing to be in unison, you need to put them all into the same 'for' loop
Code: Select all | TOGGLE FULL SIZE
for (int i = 0; i < 256; i++)
{
    pos = (i * 180) / 256;  // adjust servo position
    servo.write(pos);       // write servo
   
    strip.fill(strip.Color(i, i, i)); // write strip
    strip.show();
}

adafruit_support_bill
 
Posts: 74334
Joined: Sat Feb 07, 2009 10:11 am

Re: Motor Shield V2 + Servo + Neopixels Together?

by scotch1 on Tue Sep 10, 2019 2:02 am

nice approach! the dimming certainly corresponds to the turning direction: Seems to only turn thru 90 degrees, even if (256/2). The math would indicate that at 255 the angle of 180 would be attained,but alas, not.

Code: Select all | TOGGLE FULL SIZE
for (int i = 0; i < 256; i++)
{
    pos = (i * 179) / (255);  // adjust servo position
    servo.write(pos);       // write servo
    delay(15);
   
    strip.fill(strip.Color(i, i, i)); // write strip
    strip.show();
}

for (int i = 255; i > 0; i--)
{
    pos = (i * 179) / (255);  // adjust servo position
    servo.write(pos);       // write servo
    delay(15);
   
    strip.fill(strip.Color(i, i, i)); // write strip
    strip.show();
}


I tried to change back to i and 180 per sweep, yet, it seems to like 90 degrees:
Code: Select all | TOGGLE FULL SIZE
void setup(void) {
  servo.attach(SERVO_PIN, SERVO_MIN, SERVO_MAX);
  strip.begin();
  strip.show();            // Turn OFF all pixels ASAP
  strip.setBrightness(50); // Set BRIGHTNESS to about 1/5 (max = 255)
  servo.write(pos);       // write servo
}

void loop(void) {

for (int i = 0; i <= 180; i++)
{
    pos = (i);  // adjust servo position
    servo.write(pos);       // write servo
    delay(5);
   
    strip.fill(strip.Color(i, i, i)); // write strip
    strip.show();
}

for (int i = 180; i >= 0; i--)
{
    pos = (i);  // adjust servo position
    servo.write(pos);       // write servo
    delay(5);
   
    strip.fill(strip.Color(i, i, i)); // write strip
    strip.show();
}
delay(5);

scotch1
 
Posts: 78
Joined: Mon Nov 26, 2012 12:13 am

Re: Motor Shield V2 + Servo + Neopixels Together?

by adafruit_support_bill on Tue Sep 10, 2019 5:48 am

The other issue with mixing neopixels and servos is that writing to neopixels disables interrupts. Since the Arduino servo library relies on Arduino timer interrupts for precise servo pulse timing, this can affect servo movement. The simplest solution to that is to offload the servo pulse timing to something like a servo shield.

adafruit_support_bill
 
Posts: 74334
Joined: Sat Feb 07, 2009 10:11 am

Re: Motor Shield V2 + Servo + Neopixels Together?

by scotch1 on Wed Sep 11, 2019 1:15 am

Tried the same code on the Motor Shield V2 and same response. Are there edits to consider?

Also, tried the https://learn.adafruit.com/multi-tasking-the-arduino-part-1/a-clean-sweep approach On the motorshield V2 and the motor just stalled, no movement.

Is this the limit of Arduino with neopixels and motors?

Would like to find a solution that dims the LED while rotating through 180 deg :)


Code: Select all | TOGGLE FULL SIZE
   #include <Servo.h>

   #include <Adafruit_NeoPixel.h>
  #ifdef __AVR__
    #include <avr/power.h> // Required for 16 MHz Adafruit Trinket
  #endif

// Which pin on the Arduino is connected to the NeoPixels?
// On a Trinket or Gemma we suggest changing this to 1:
  #define LED_PIN     7

// How many NeoPixels are attached to the Arduino?
  #define LED_COUNT  7

// NeoPixel brightness, 0 (min) to 255 (max)
  #define BRIGHTNESS 255

// Declare our NeoPixel strip object:
Adafruit_NeoPixel strip(LED_COUNT, LED_PIN, NEO_GRBW + NEO_KHZ800);

class Flasher
{
 // Class Member Variables
  // These are initialized at startup
  int ledPin;      // the number of the LED pin
  long OnTime;     // milliseconds of on-time
  long OffTime;    // milliseconds of off-time

  // These maintain the current state
  int ledState;                 // ledState used to set the LED
  unsigned long previousMillis;   // will store last time LED was updated

  // Constructor - creates a Flasher
  // and initializes the member variables and state
  public:
  Flasher(int pin, long on, long off)
  {
  ledPin = pin;
  pinMode(ledPin, OUTPUT);     
   
  OnTime = on;
  OffTime = off;
 
  ledState = LOW;
  previousMillis = 0;
  }

  void Update()
  {
    // check to see if it's time to change the state of the LED
    unsigned long currentMillis = millis();
     
    if((ledState == HIGH) && (currentMillis - previousMillis >= OnTime))
    {
      ledState = LOW;  // Turn it off
      previousMillis = currentMillis;  // Remember the time
      digitalWrite(ledPin, ledState);  // Update the actual LED
    }
    else if ((ledState == LOW) && (currentMillis - previousMillis >= OffTime))
    {
      ledState = HIGH;  // turn it on
      previousMillis = currentMillis;   // Remember the time
      digitalWrite(ledPin, ledState);   // Update the actual LED
    }
  }
};

class Sweeper
{
  Servo servo;              // the servo
  int pos;              // current servo position
  int increment;        // increment to move for each interval
  int  updateInterval;      // interval between updates
  unsigned long lastUpdate; // last update of position

public:
  Sweeper(int interval)
  {
    updateInterval = interval;
    increment = 1;
  }
 
  void Attach(int pin)
  {
    servo.attach(pin);
  }
 
  void Detach()
  {
    servo.detach();
  }
 
  void Update()
  {
    if((millis() - lastUpdate) > updateInterval)  // time to update
    {
      lastUpdate = millis();
      pos += increment;
      servo.write(pos);
      Serial.println(pos);
      if ((pos >= 180) || (pos <= 0)) // end of sweep
      {
        // reverse direction
        increment = -increment;
      }
    }
  }
};
 
 
Flasher led1(11, 123, 400);
Flasher led2(12, 350, 350);
Flasher led3(13, 200, 222);

Sweeper sweeper1(15);
Sweeper sweeper2(25);
 
void setup()
{
  Serial.begin(9600);
  sweeper1.Attach(9);
  sweeper2.Attach(10);

    // These lines are specifically to support the Adafruit Trinket 5V 16 MHz.
  // Any other board, you can remove this part (but no harm leaving it):
  #if defined(__AVR_ATtiny85__) && (F_CPU == 16000000)
    clock_prescale_set(clock_div_1);
  #endif
  // END of Trinket-specific code.

  strip.begin();           // INITIALIZE NeoPixel strip object (REQUIRED)
  strip.show();            // Turn OFF all pixels ASAP
  strip.setBrightness(255); // Set BRIGHTNESS to about 1/5 (max = 255)
 
}
 
 
void loop()
{
  sweeper1.Update();
  sweeper2.Update();
 
  led1.Update();
  led2.Update();
  led3.Update();

  pulseWhite(5);
}


void pulseWhite(uint8_t wait) {
  for(int j=0; j<256; j++) { // Ramp up from 0 to 255
    // Fill entire strip with white at gamma-corrected brightness level 'j':
    strip.fill(strip.Color(0, 0, 0, strip.gamma8(j)));
    strip.show();
    delay(wait);
  }

  for(int j=255; j>=0; j--) { // Ramp down from 255 to 0
    strip.fill(strip.Color(0, 0, 0, strip.gamma8(j)));
    strip.show();
    delay(wait);
  }
}

scotch1
 
Posts: 78
Joined: Mon Nov 26, 2012 12:13 am

Re: Motor Shield V2 + Servo + Neopixels Together?

by adafruit_support_bill on Wed Sep 11, 2019 5:54 am

Tried the same code on the Motor Shield V2 and same response. Are there edits to consider?

The motor shield doesn't change anything. It uses the same Arduino Servo library and Arduino Timers. To avoid interrupt contention between servos and Neopixels you would need to use something like the Servo Shield to off-load the servo pulse timing as suggested above. https://www.adafruit.com/product/1411

adafruit_support_bill
 
Posts: 74334
Joined: Sat Feb 07, 2009 10:11 am

Re: Motor Shield V2 + Servo + Neopixels Together?

by scotch1 on Wed Sep 11, 2019 2:00 pm

Thanks Bill:
Guess I didn't understand the difference when I bought the MotorShield V2 and it didn't work for a shake table application and should have went with the suggested Servo Shield for both this application and likely better for the Shake table.
Are you saying that the same code will result in the servo turning 180 as intended and the neopixel dimming in unison?
Will add to cart if so.
Michael

scotch1
 
Posts: 78
Joined: Mon Nov 26, 2012 12:13 am

Re: Motor Shield V2 + Servo + Neopixels Together?

by adafruit_support_bill on Wed Sep 11, 2019 2:09 pm

Are you saying that the same code will result in the servo turning 180 as intended and the neopixel dimming in unison?

The Servo Shield uses a different library, so you will need to make some changes to your code.

Using the Servo Shield will eliminate any timing interference between the neopixels and servos. Whether that gets you a full 180 degrees depends on the servo you are using. Are you able to turn your servo 180 degrees using the Servo library without any Neopixels?

adafruit_support_bill
 
Posts: 74334
Joined: Sat Feb 07, 2009 10:11 am

Re: Motor Shield V2 + Servo + Neopixels Together?

by scotch1 on Thu Sep 12, 2019 12:51 am

Not exactly 180 degrees, seems to be something close to 170 degrees which I thought Odd, but may be the twr pro issue.
Are you able to advise on the code changes as I have ordered a servo shield and would like to demo it Friday AM to the team for consideration of function. :)

scotch1
 
Posts: 78
Joined: Mon Nov 26, 2012 12:13 am

Re: Motor Shield V2 + Servo + Neopixels Together?

by adafruit_support_bill on Thu Sep 12, 2019 6:21 am

Yes, many of the Tower servos don't have a full 180 degree range.

You can use the declarations and setup logic from the example code in the library.
https://github.com/adafruit/Adafruit-PW ... /servo.ino

Your sweep logic would look something like:
Code: Select all | TOGGLE FULL SIZE
for (int i = 0; i < 256; i++)
{
   pos = (i * 180) / 256;  // adjust servo position
   int pulselength = map(pos, 0, 180, SERVOMIN, SERVOMAX);
   pwm.setPWM(servonum, 0, pulselen);

   strip.fill(strip.Color(i, i, i)); // write strip
   strip.show();
}

adafruit_support_bill
 
Posts: 74334
Joined: Sat Feb 07, 2009 10:11 am

Re: Motor Shield V2 + Servo + Neopixels Together?

by scotch1 on Thu Sep 12, 2019 5:38 pm

Thanks Bill!
Shield Arrived today, will test tonight, demo tomorrow :)

scotch1
 
Posts: 78
Joined: Mon Nov 26, 2012 12:13 am

Re: Motor Shield V2 + Servo + Neopixels Together?

by scotch1 on Sat Sep 14, 2019 7:26 pm

So: plugged in the soldered shield and tried to run the tests and getting nothing.
providing added 6 v thru 4 x 1.5 V battery pack.
Tried the various ways to address it. Don't believe that one shield needs a jumper, does it? Tried connecting a wire across the first jumper and nothing. Sporadic servo twitching on a re-plug in.
Tutorial: https://learn.adafruit.com/adafruit-16-channel-pwm-slash-servo-shield/using-the-adafruit-library
Servo works with the basic Sweep sketch on the motor shield. V2
Using these servos:
https://servodatabase.com/servo/towerpro/sg90
Pic attached, don't seem to have a solder issue.
red_72101.jpg
red_72101.jpg (78.84 KiB) Viewed 21 times
red_72104.jpg
red_72104.jpg (166.39 KiB) Viewed 21 times
red_72103.jpg
red_72103.jpg (119.38 KiB) Viewed 21 times

What could be the issue? happy to mail for testing

scotch1
 
Posts: 78
Joined: Mon Nov 26, 2012 12:13 am

Re: Motor Shield V2 + Servo + Neopixels Together?

by adafruit_support_bill on Sun Sep 15, 2019 6:15 am

What type of Arduino are you using with the shield? Have you tried the example code from the PWM/Servo shield library?

Are both the V+ and VCC LEDs on the board lit?

adafruit_support_bill
 
Posts: 74334
Joined: Sat Feb 07, 2009 10:11 am

Please be positive and constructive with your questions and comments.