Animatronic Velociraptor

Hello
I am trying to control 5 DC motors (in an animatonic dino) via their motor controllers using the analogue outputs from an UNO. The DC maximum input to these controllers is 3 V. I have written a code which ramps three of the motors up and down. One of the motors (jaw), ramps up but needs to stop on a PNP sensor. This sensor signal I am passing to a relay which pulls pin 12 down. Pin 12 is being monitored by an ISR. The eyes also blink and have a PNP sensor which is being monitored by an ISR, this motor doesn't have an analogue input so I am switching it on and off using the power shield.

I am finding, despite a good signal in, the UNO doesn't always respond and also the motors can stutter and slow down. I am getting really frustrated (not an experienced coder) and am desperate for help.

Best regards

Rob

Show us your code. Use the code tags like it says in the "How to use this forum - please read." post at the top of this forum.

Show us your wiring diagram. A picture of a hand drawn diagram is fine.

Here is my code. I have been chopping at it quite a bit trying to eliminate possible issues. Also I have noticed that random () is bring back numbers outside the defined parameters like 0??

I shall draw a schematic when I get to work tomorrow.

Thank you for your help

Rob

/*
 * NOTES :- 
 * Analogue pwm outputs- jaw=10, neck=5, tail=6, torso=9
 * Digital outputs- eyes = 4,
 * Digital inputs- eyes=3, jaw=2, Current ISRs
 */
#include <stdio.h>

int state[5] = {0,0,0,0,0};//State of motors.  0=OFF,1=ON.  Initialised to OFF!
int outputs[5] = {1,2,3,4,5};//1=eyes,2=jaw,3=neck,4=tail,5=torso
const byte eyeSensor = 3;
const byte jawSensor = 2;

void setup()
{
  Serial.begin(115200);//For debugging purposes.  Remove when complete!
  pinMode(3,OUTPUT);pinMode(5,OUTPUT);pinMode(6,OUTPUT);pinMode(9,OUTPUT);pinMode(10,OUTPUT);
  //pinMode(2,INPUT_PULLUP);//Pulls jawsSensor pin up to 5 V tp prevent erroneous signals
  pinMode(12,OUTPUT);//trigger sound card/roar
  digitalWrite(12,HIGH);
  //pinMode(11,INPUT_PULLUP);//Pulls eyeSensor pin up to 5 V to prevent erroneous signals
  pinMode(4,OUTPUT);
  digitalWrite(4,LOW);
  pinMode(eyeSensor,INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(eyeSensor),eyeStop,FALLING);
  pinMode(jawSensor,INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(jawSensor),jawStop,FALLING);
}

void loop()
{/*
  int func = random(1,6);
  if(func == 1)eyeFunc();
  else if(func == 2)jawFunc();
  else if(func == 3)neckFunc(state[2]);
  else if(func == 4)tailFunc(state[3]);
  else if(func == 5)torsoFunc(state[4]);*/
  
  //subroutines used for debugging purposes
  
  //eyeFunc();
    //digitalWrite(4,HIGH);
  jawFunc();
    //analogWrite(10,153);
  //neckFunc(state[2]);
  //tailFunc(state[3]);
  //torsoFunc(state[4]);
  //delay(500);
}

int eyeFunc()
{
  digitalWrite(4,HIGH);
  Serial.println("start");
}

void eyeStop()
{
  digitalWrite(4,LOW);
  Serial.println("stop");
}

int jawFunc()
{
  int i;
  for(i=0;i<=153;i=i+2)
  {
    analogWrite(10,i);
  }
}

void jawStop()
{
  analogWrite(10,0);
}

int neckFunc(int& state3)
{
  int i;
  int rate;
  //Serial.println("neck = "state3");
  if(state3==0)//Checks motor status and starts/stops accordingly
  {
    rate =1;
    for(i=0;i<=153;i++)
    {
      analogWrite(5,i);
      delay(30);
    }
    state3 = 1;
  }
    
  else if(state3==1)
  {
    rate = -1;
    for(i=153;i>=0;i--)
    {
      analogWrite(5,i);
      delay(30);
    }
    state3 = 0;
  }
}

int tailFunc(int& state4)
{
  int i;
  int rate;
  if(state4==0)//Checks motor status and starts/stops accordingly
  {
    rate =1;
    for(i=0;i<=120;i++)
    {
      analogWrite(6,i);
      delay(30);
    }
    state4 = 1;
  }
    
  else if(state4==1)
  {
    rate = -1;
    for(i=120;i>=0;i--)
    {
      analogWrite(6,i);
      delay(30);
    }
    state4 = 0;
  }
}


int torsoFunc(int& state5)
{
  int i;
  int rate;

  if(state5==0)//Checks motor status and starts/stops accordingly
  {
    rate =1;
    for(i=0;i<=153;i++)
    {
      analogWrite(9,i);
      delay(30);
    }
    state5 = 1;
  }
    
  else if(state5==1)
  {
    rate = -1;
    for(i=153;i>=0;i--)
    {
      analogWrite(9,i);
      delay(30);
    }
    state5 = 0;
  }
}
    for(i=153;i>=0;i--)

{
      analogWrite(9,i);
      delay(30);
    }

153 delays of 30 milliseconds is quite some time to spend with all the sensors disabled. Open up the Blink_Without_Delay example and read it well. You seem to have a relatively complex robot so converting every function to work without delay is going to be a big effort. Unfortunately it is necessary to remove every delay.

thelittlesthobo:
Also I have noticed that random () is bring back numbers outside the defined parameters like 0??

What makes you think that is happening? I don't see you printing that out anywhere. How do you know it is giving 0's?

Delta_G:
What makes you think that is happening? I don't see you printing that out anywhere. How do you know it is giving 0's?

I was using Serial.println(func); and it was showing the occasional 0. Although I can't prove it now as it isn't doing it anymore. Perhaps something I chopped out.

MorganS:
153 delays of 30 milliseconds is quite some time to spend with all the sensors disabled. Open up the Blink_Without_Delay example and read it well. You seem to have a relatively complex robot so converting every function to work without delay is going to be a big effort. Unfortunately it is necessary to remove every delay.

So I've been writing the for loop again trying to use millis() instead of delay(), which is quite complicated. My question is....why use millis() within a for loop? I understand using it within loop(), but isn't the process stuck in the loop until the exit condition is reached ( I <= 153) and therefore unable to carry out any parallel activity?

Yeah you wouldn't use a for loop either. Let the loop function handle the looping and just take one step per loop.

Either way, my loops now look like this. My real problem is that the jaw stutters and the eyes and jaw are not always stopping in the home position, they appear to be doing their own thing! Schematic to follow...

int jawFunc()
{
  int i;
  unsigned long startTimer, stopTimer;
    const long loopDelay = 5;
    startTimer = millis();
    
  for(i=0;i<=153;)
  {
    analogWrite(10,i);
    stopTimer = millis();
      if(stopTimer - startTimer > loopDelay)
      {
        i += 1;
        startTimer = stopTimer;
      }
  }
}

You just wrote your own version of delay().

You need to convert all of the actions to "states" where the eyes might be in a "moving-left" state and the jaw in "moving-up" state. Depending on what state it's in and how long it was since one of those last moved, you may change the commanded position for one or both inside one run through loop().

Think about writing functions like if(timeForJawToMove()) moveJaw(); and that move only moves one step, possibly updating the state if it gets to the end of the movement.

Here is the schematic. Both the jaw and eyelids have PNP sensors (24 V) running through the NC terminals of a relay and connected to digital pins 2 and 3 with external interrupts. Question. Will a DC motor controller be happy with a PWM signal. I am told that they are 0 - 3 V analogue input signal, hence the 153 limit on the for loops. Also I have no tech specs on the motor controllers, Chinese crap came with dinosaurs!

You understand that analogWrite(pinNo, 153) won't actually output 3 volts? It will output a square wave with a 60% duty cycle but the peak voltage is 5V. If you feed that to a motor or other analog filter it will behave as if you gave it 3V. If you feed that to a digital input with a maximum voltage of 3V then you are overloading that input.

Yes, it's going to an analogue input.

Then you may have damaged that 3V input. (Unlikely.)

Try this...

const int JawClosedPosition = 153; //don't move the jaw past these analogWrite() limits
const int JawOpenedPosition = 0;
const int JawCloseSpeed = 30; //milliseconds - make this larger for slower movement of the jaw
const int JawOpenSpeed = 30; //milliseconds - make this larger for slower movement of the jaw
const int PinJaw = 10; //Jaw motor controller is on this pin
int jawFunc(boolean jawClose) {
  //move the jaw by one step in the intended direction, if required
  //return very quickly (nanoseconds) if there's no step taken
  static int currentPosition = JawClosedPosition;
  static unsigned long startTimer = 0;

  if(jawClose) {
    //move the jaw in the closing direction at constant speed
    //if at the end of travel, stop and do nothing
    if(currentPosition <= JawClosedPosition) {
      if(millis() - startTimer > JawCloseSpeed) {
        //time to take a step
        currentPosition++;
        analogWrite(PinJaw, currentPosition);
        startTimer = millis();
      } //else we don't need to take a step now
    } //else we've reached the closed position
  } else {
    //jaw is opening
    if(currentPosition >= JawOpenedPosition) {
      if(millis() - startTimer > JawOpenSpeed) {
        //time to take a step
        currentPosition--;
        analogWrite(PinJaw, currentPosition);
        startTimer = millis();
      } //else we don't need to take a step now
    }
  }
}