C++ question building a derived class

I’m totally flummoxed.

I am working on a basic servo extension to coordinate multiple servos; right now they are just one LEFT and one RIGHT.

I have a bug somewhere but I cannot find it. I’m at that 2nd set of eyes point, so I appreciate any help.

Basically, I am trying to get multiple servos to respond to simple commands in unison. Right-handed servos will sweep opposite to Left-handed in an “syncronized” manor. I hope you get it. My problem, and if you take the time to flash the code, you can see from the (I’m using Photon here, 0.6.1) Serial output that I cannot get just the left servo to move. Both move… Right moves… Left won’t move. I know it is something grossly simple that I have stared at for just too damned long.

I’m hoping that fresh eyes prevail!

example.ino

#include "Brazos.h"

Brazos right(RIGHT_HAND);
Brazos left(LEFT_HAND);

uint32_t rightPosition = 0, leftPosition = 0;

void setup(void)
{
  Serial.begin(9600);
  Particle.variable("rightPos", rightPosition);
  Particle.variable("leftPos", leftPosition);
  Particle.function("MoveHands", moveHands);
  right.begin(D2, A2);
  left.begin(D3, A3);
  right.write(0);
  left.write(180);
  delay(3000);
  Brazos::moveAll(HAND_UP);
  Serial.printf("There %s %d %s attached\n", Brazos::getInstanceCount() == 1? "is" : "are", Brazos::getInstanceCount(), Brazos::getInstanceCount() == 1? "servo" : "servos");
}

void loop(void)
{
  Brazos::update(millis());
  rightPosition = right.read();
  leftPosition = left.read();

}

int moveHands(const String command)
{
  char myCommand[256] = "";
  command.toCharArray(myCommand, sizeof(myCommand));
  Brazos* selectedHand;
  if(strstr(myCommand, "right"))
  {
    selectedHand = &right;
    Serial.println("selected Right");
  }
  else if(strstr(myCommand, "left"))
  {
    selectedHand = &left;
    Serial.println("selected Left");
  }
  else
  {
    selectedHand = NULL;
    Serial.println("selected Both");
  }
  if(strstr(myCommand, "up"))
  {
    if(selectedHand)
      selectedHand->move(HAND_UP);
    else
      selectedHand->moveAll(HAND_UP);
  }
  else if(strstr(myCommand, "down"))
  {
    if(selectedHand)
      selectedHand->move(HAND_DOWN);
    else
      selectedHand->moveAll(HAND_DOWN);
  }
  else if(strstr(myCommand, "point"))
  {
    if(selectedHand)
      selectedHand->move(HAND_POINT);
    else
      selectedHand->moveAll(HAND_POINT);
  }
  return 1;
}

Brazos.h (“arm”)

#ifndef BRAZOS_H
#define BRAZOS_H
#include <vector>
#include "Particle.h"

#define MOTION_SPEED_INTERVAL 5

enum Mano{
  RIGHT_HAND,
  LEFT_HAND
};

enum HandCommand{
  HAND_UP,
  HAND_DOWN,
  HAND_POINT,
  HAND_MASHED_POTATO,
};

class Brazos : public Servo {

  public:
    enum MotionState{
      ARM_AT_REST,
      ARM_MOVING
    };
    Brazos(Mano mano);
    ~Brazos();
    void begin(int servo, int input);
    void move(HandCommand command);
    static void moveAll(HandCommand command);
    static void update(uint32_t now);
    static int getInstanceCount();

  private:
    static std::vector< Brazos* > instanceAddress;
    Mano _mano;
    int servoPin;
    int inputPin;
    MotionState motionState = ARM_MOVING;
    uint32_t lastMotionMillis = 0;
    int currentPositon;
    int targetPosition;
    static void setTargetPosition(Brazos* instance, int position);
};

#endif

Brazos.cpp

#include "Brazos.h"
#include <vector>
#include "Particle.h"

std::vector< Brazos* > Brazos::instanceAddress;

Brazos::Brazos(Mano mano)
{
  instanceAddress.push_back(this);
  _mano = mano;
}

Brazos::~Brazos(void)
{
  // TO DO Erase vector element instanceAddress <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
}

int Brazos::getInstanceCount()
{
  return instanceAddress.size();
}

void Brazos::begin(int servo, int input)
{
  servoPin = servo;
  pinMode(servoPin, OUTPUT);
  attach(servoPin);
  inputPin = input;
}

void Brazos::move(HandCommand command)
{
  int newPosition = 0;
  switch(command)
  {
    case HAND_UP:
      newPosition = 180;
      break;
    case HAND_DOWN:
      newPosition = 0;
      break;
    case HAND_POINT:
      newPosition = 90;
      break;
    default:
      //
      break;
  }
  Serial.println("setting new servo target position");
  setTargetPosition(this, newPosition);
}

void Brazos::setTargetPosition(Brazos* instance, int position)
{
  instance->targetPosition = (instance->_mano == RIGHT_HAND)? position : 180 - position;
  Serial.println("Just set instance servo target position");
}

void Brazos::moveAll(HandCommand command)
{
  for(int i = 0; i < instanceAddress.size(); i++)
  {
    int newPosition = 0;
    switch(command)
    {
      case HAND_UP:
        newPosition = 180;
        break;
      case HAND_DOWN:
        newPosition = 0;
        break;
      case HAND_POINT:
        newPosition = 90;
        break;
      default:
        //
        break;
    }
    instanceAddress[i]->setTargetPosition(instanceAddress[i], newPosition);
  }
}

void Brazos::update(uint32_t now)
{
  for(int i = 0; i < instanceAddress.size(); i++)
  {
    if(now - instanceAddress[i]->lastMotionMillis > MOTION_SPEED_INTERVAL)
    {
      if(instanceAddress[i]->targetPosition == instanceAddress[i]->currentPositon)
      {
        if(instanceAddress[i]->attached())
        {
          instanceAddress[i]->detach();
          Serial.printf("Servo:%d Detached\n", i);
        }
        return;
      }
      if(!instanceAddress[i]->attached())
      {
        instanceAddress[i]->attach(instanceAddress[i]->servoPin);
        Serial.printf("Servo:%d Attached\n", i);
      }
      Serial.printf("Servo:%02d\tCurrent Position:%03d\tTarget Position:%03d\n", i, instanceAddress[i]->currentPositon, instanceAddress[i]->targetPosition);
      if(instanceAddress[i]->targetPosition > instanceAddress[i]->currentPositon)
      {
        instanceAddress[i]->currentPositon++;
        instanceAddress[i]->write(instanceAddress[i]->currentPositon);
      }
      else
      {
        instanceAddress[i]->currentPositon--;
        instanceAddress[i]->write(instanceAddress[i]->currentPositon);
      }
      instanceAddress[i]->lastMotionMillis = now;
    }
  }
}

It seems to me that I am simply not traversing the instanceAddress vector in my update() function.

Thanks for reading this!

void Brazos::update(uint32_t now)
{
  for(int i = 0; i < instanceAddress.size(); i++)
  {
    if(now - instanceAddress[i]->lastMotionMillis > MOTION_SPEED_INTERVAL)
    {
      if(instanceAddress[i]->targetPosition == instanceAddress[i]->currentPositon)
      {
        if(instanceAddress[i]->attached())
        {
          instanceAddress[i]->detach();
          Serial.printf("Servo:%d Detached\n", i);
        }
        return;  //<<<<<<<<<<<<<<<<<<<<<<<<<<<< Nope!
      }
      if(!instanceAddress[i]->attached())

fresh look this am, I realized that I wan’t allowing the function to traverse the 2nd element of the vector.

:slight_smile:

Too late to be helpful then? :wink: :+1:

1 Like

well, I’m not finished yet!

:grin:

1 Like