TIP-120 bi-direction motor control

I posted a motor control routine to this forum earlier, I used a joystick, however the motor section could easily be adapted to use fixed rate speeds.

Grumpy_Mike:

I want to use a pair of these to drive a motor.

How are you going to wire it up? I am not sure you can do it with only two transistors.

I know I am a little late on this - but it is possible to use only two transistors to control a DC motor's direction; it's called a half-bridge circuit (and your power supply must be dual-ended). Back in the day, they used such a circuit on the Milton Bradley Big Trak toy - because it was cheaper to build (transistors weren't super expensive at the time, they were just cutting corners to increase profitability, most likely). The toy ran on four D-cell's, with the pack "split" in the middle, that mid-point being "ground" for the motor driver circuitry, leaving +/- 3 VDC for the motors. The transistors switched this to change the motor's direction (the controller used on the toy ran on its own separate 9 volt battery).

This did have a side effect, though: If you constantly made turns in one particular direction (say, a lot of turns in the clockwise direction), you would drain one side of the pack faster than the other, which would lead to the pack trying to self-charge and stabilize, but ultimately causing the batteries to wear out very quickly (which must've made Duracell very happy).

This issue (and the need for a dual-ended supply - plus the cost difference being moot today anyhow) is why you don't generally see the setup used anymore...

:slight_smile:

Near the same time would be acceptable for this project but I can't get this to work:

So what happens?
Put some print statements in to see if you are getting into the correct case statement. The code as posted looks fine.

Yeah, I guess that wasn't very elaborate. What happens is; the first part of the operation will run but he 2nd part never does.

As in:

case 't':    
      digitalWrite(2, HIGH);
      digitalWrite(3, HIGH);
      break;

The 2nd pin fires, but not the 3rd. :drooling_face:

Oh and after some assembly time, I finally got to drive this thing around Monday night, it works perfectly! Thank you all for all of the help,
I feel like I have learned a few things too. =D

So, its time to take this code a step farther. Everything in the following code works perfectly for me. I am currently controlling 2
motors with the option to add another 2 motors, hence the 2x (Res) entries. I would like to add 2 servos into the mix, one on
Pin 5 and one on Pin 6.

#include <AFMotor.h>

AF_DCMotor motor1(1, MOTOR12_64KHZ); // create motor #1, 64KHz pwm 
AF_DCMotor motor2(2, MOTOR12_64KHZ); // create motor #2, 64KHz pwm 
AF_DCMotor motor3(3, MOTOR12_1KHZ);  // create motor #3, 1KHz pwm (Res)
AF_DCMotor motor4(4, MOTOR12_1KHZ);  // create motor #4, 1KHz pwm (Res)

void setup() {
  Serial.begin(9600);           // set up Serial library at 9600 bps
}

void loop() {
  // read the sensor:
  if (Serial.available() > 0) {
    int inByte = Serial.read();

    int speed; // Local variable

    //Motor 1 - Full Speed

      switch (inByte) {
    case 'w':   
      motor1.setSpeed(225);
      motor1.run(FORWARD);     // Motor Runs Forward
      break;

    case 'k':   
      motor1.run(RELEASE);     // Motor Stops
      break;

    case 's':   
      motor1.setSpeed(225);
      motor1.run(BACKWARD);    // Motor Runs Backwards
      break;

      //Motor 2 - Full Speed

    case 'e':   
      motor2.setSpeed(225);
      motor2.run(FORWARD);     // Motor Runs Forward
      break;

    case 'l':   
      motor2.run(RELEASE);     // Motor Stops
      break;

    case 'd':   
      motor2.setSpeed(225);
      motor2.run(BACKWARD);    // Motor Runs Backwards
      break;

    default:
      // turn all the connections off:
      for (int thisPin = 2; thisPin < 7; thisPin++) {
        digitalWrite(thisPin, LOW);
      }
    }
  }
}

I know I have to add:

#include <Servo.h>
 
Servo myservo1;  // create servo object to control servo1
Servo myservo2;  // create servo object to control servo2

But as to where and not interrupt the motor code I am not sure. Do you add it to this instance or add it to a following instance?
Btw I am calling everything between the "}" instances.

Can I add the
#include <Servo.h> after the #include <AFMotor.h>
and the

Servo myservo1;  // create servo object to control servo1
Servo myservo2;  // create servo object to control servo2

after the

AF_DCMotor motor1(1, MOTOR12_64KHZ); // create motor #1, 64KHz pwm 
AF_DCMotor motor2(2, MOTOR12_64KHZ); // create motor #2, 64KHz pwm 
AF_DCMotor motor3(3, MOTOR12_1KHZ);  // create motor #3, 1KHz pwm (Res)
AF_DCMotor motor4(4, MOTOR12_1KHZ);  // create motor #4, 1KHz pwm (Res)

and just add entries like

case 'T':   
      myservo1.run(FORWARD);    // Servo Runs Forward
      break;

after

switch (inByte) {
    case 'w':   
      motor1.setSpeed(225);
      motor1.run(FORWARD);     // Motor Runs Forward
      break;

Thank you for your help in Advance. :%
-Ec7

Mostly yes, but not this...

case 'T':   
      myservo1.run(FORWARD);    // Servo Runs Forward
      break;

Look up the servo library in the reference section.

Yes, but I am not looking for it to move from one position to another, I am wondering if you can move it similar to a motor

Press T and it will move in desired direction
maybe press Y and it will stop.

  for(pos = 0; pos < 180; pos += 1)  // goes from 0 degrees to 180 degrees
  {                                  // in steps of 1 degree
    myservo.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>=1; pos-=1)     // goes from 180 degrees to 0 degrees
  {                                
    myservo.write(pos);              // tell servo to go to position in variable 'pos'
    delay(15);

Above reference code not quite it.

Can the code be edited like

case 'T':
myservo1.write(Forward);
break;

case 'Y'
myservo1.write(RELEASE)
break;

case 'U':
myservo1.write(Backwards);
break;

Possible?

Yes, but I am not looking for it to move from one position to another, I am wondering if you can move it similar to a motor

There are two kinds of servos. Real servos and continuous rotation "servos". Continuous rotation "servos" aren't really servos any more.

Servos can not be "run like motors". "Servos" can.

Servos are meant to control things like steering or throttle. Neither of these are possible scenarios for "just run like a motor".

Referring to the continuous rotation, or previously stated
"broken" servos. I can use these because they still fit into the
bracket and I have 2 laying around.

Can you somehow drive a pin high / low to control it?

Basically this is a pan / tilt assembly for a camera and i need
it to work similar to the previous motor code that I was working
on.

Ideas?

I have 2 "broken servos" and 2 180 degree servos. the nice idea
about the 180 degree servos is that it would only allow the cam to
turn 90 degrees in either direction and would avoid tangling cables.

Continuous rotation servos are still driven with the servo library. One 'position' (usually around 90) represents 'stop', then positions higher or lower than 'stop' give proportionally higher speed in one direction or the other.

Problem solved. I took the continuous servo apart and wired directly to the motor. Now I can just control it the same way I control my other motors.

Okay back to servos.

This should actually be possible:

Press a key to have the servo move to and stop on a pre-defined degree.

say press X and the servo will move to 0

Press Y and the servo will move to 90

Press Z and it will move to -90

Something like:

#include <Servo.h>
 
Servo myservo1;  // create servo object to control a servo

void setup() {
  Serial.begin(9600);           // set up Serial library at 9600 bps

void loop() {
  // read the sensor:
  if (Serial.available() > 0) {
    int inByte = Serial.read();

switch (inByte) {

case 'X':
myservo.write(0);              // tell servo to go to position 0
    delay(15);

case 'Y':
myservo.write(90);              // tell servo to go to position 90
    delay(15);

case 'Z':
myservo.write(-90);              // tell servo to go to position -90
    delay(15);

Servo.write() takes an argument from 0 to 180 (representing degrees) which are the extremes of the servo travel, 90 degrees is in the middle.

JFYI Servo.write will interpret any value that is out of band for degrees of movement as time in microseconds. So ensure adequate constraints on any value calculated and passed to the servo class.

Good Evening, It's been awhile.

I would like to revisit and continue the Servo idea.

Take a servo and control it (move to X degree) when you press a keyboard key, (Move to Y degree) when you press another. (Working Code Below)

I am also interested in learning how to make it move in X number of degrees until a stop button has been pressed.

The following code will move to 90 degrees when q is pressed and 170 when w is pressed. How could you add an interrupt that would stop the servo if a digital button was pressed say before it go to 170 degrees? (like its traveling and stop it at 136 degrees) [This is for a robotic claw that I want to pick objects up without crushing them / straining the servo]

#include <Servo.h>
 
Servo myservo;  // create servo object to control a servo
                // a maximum of eight servo objects can be created
 
int pos = 0;    // variable to store the servo position

void setup() {
Serial.begin(9600); // Setup Serial library at 9600 bps 
} 
 
void loop() { 
  // read the IO: 
  if (Serial.available() > 0) { 
    int inByte = Serial.read(); 
    for (int thisPin = 9; thisPin < 11; thisPin++) {
    pinMode(thisPin, OUTPUT);

switch (inByte) { 
    case 'q':    
    	myservo.attach(9);
	myservo.write(90);  // set servo to mid-point
	 break; 

    case 'w':    
    	myservo.attach(9);
	myservo.write(170);  // set servo to mid-point
	 break; 

 	  default: 
      // turn all the connections off (Except Motorshield): 
      for (int thisPin = 9; thisPin < 11; thisPin++) { 
        digitalWrite(thisPin, LOW); 
		
		}
		}
		}}}

Thanks =)

How could you add an interrupt that would stop the servo if a digital button was pressed say before it go to 170 degrees?

Easy. You write the code is a way that does NOT require interrupts. Move the servo a little. See if the servo should be moved some more (the switch is not pressed). If so. move it some more. If not, don't.

Hello again PaulS.

The thinking I had behind interrupts was that perhaps I could add a timing mechanism to the code so that if: Claw closes, the button is in the claw, claw closes on an object and presses the button, timer is allowing the servo to move a few more milliseconds, this allows the claw to "grip". To reverse this; hit the other key and claw opens to repeat the process all over again. - My thinking anyways.

Possible?

Possible?

Anything's possible. But, let's discuss what is really needed. How soon after contact do you need to know that contact has occurred? With an interrupt, you'd know within nanoseconds. Is that necessary? How soon can you set a flag that loop() checks to determine that it needs to do something different? Is that less than the time needed to determine, using polling, that loop() needs to do something different?

I don't think it has to be extremely precise. It needs to not damage the servo by trying to close the claw on an object (and not shutting down), but allow enough time to "grip" said object. I am also hoping to have it be adjustable.

Teach me the:

How soon can you set a flag that loop() checks to determine that it needs to do something different? Is that less than the time needed to determine, using polling, that loop() needs to do something different?

and I will give it a shot.

Thank you.

Teach me the:

I don't understand what you are asking.

If you use an interrupt, you can do something when the interrupt happens. When the interrupt is over, the program resumes executing where it was before the interrupt occurred. You can not change that.

What you can do, in the interrupt service routine, is to set a flag.

In loop(), or other functions, you can periodically, check the status of the flag. If it is true, do one thing (maybe return). If it is false, do something else.

Of course, instead of checking a flag, you could check the pin state.

In your program, you could have the switch trigger an interrupt. In the interrupt handler, you can not make the claw stop closing. All you can do is set a flag that says that the claw should stop closing.

In the "close the claw" function, you might have a while loop that is moving the claw in small increments.

while(clawNotFullyClosed)
{
}

With the interrupt method, you'd change that to

while(clawNotFullyClosed && !clawIsToStop)
{
}

You's set clawIsToStop to false before this loop, and you'd set it to true in the ISR.

With polling, you'd use

while(clawNotFullyClosed && digitalRead(clawSwitch) != HIGH)
{
}

Or LOW, depending on how the switch is wired.

I think that you can see that, in this case, using interrupts buys you nothing. You won't know whether the switch was closed and interrupt has been triggered any sooner than you'd learn that the switch was closed.

Good morning,

In the interrupt handler, you can not make the claw stop closing. All you can do is set a flag that says that the claw should stop closing.

Oh that's not good. It kind of sounds like what happened out at Chernobyl. "We sent the command, the indicator light came on; Maybe the valve is open?"

You won't know whether the switch was closed and interrupt has been triggered any sooner than you'd learn that the switch was closed.

I am needing this so that the unit does not damage its self. I could program it in with the user in control; as long as you press X the claw closes, but this leave way to much room for error (user error, latency in sending the command over wireless, etc)

Originally I was going to use a motor and do the "as long as you press X the claw closes" trick. I was going to wire said motor so that both the + and the - had 2 leads. I would then wire a momentary button to one of the leads so that when the claw closed on something it would depress and the power would be cut to the motor. The other 2 leads could then be powered by another button press "Y"(that would be programmed to drive the pin of the first set of powered leads to Low) so that you could still be able to reopen the claw and release its grip on an object. X to close, Y to open.

Instead I figured I would be able to do this in software and learn a more sophisticated way of doing things. There has to be a way of accomplishing such a simple task =)