Servos
Diagram Servo Test Sketch Servo Test

I'll be using MG996 servos for DC automation, because they are relatively hi-torque and I am familiar with them.   I'll mount the servo on the side of the updraft valve on a 3/16" thick piece of plywood.   Please check out the diagram.      

A while back I bought a roll of steel wire (9 AWG) from Lowes, this would make great actuator rods (linkage) for the updraft valves.   I'll weld a 3mm x 10mm machine screw to the end of (at 90°) to thread into the actuator arm.   I know that'll be ugly, I don't weld often enough to be good, but it should work.   When the servo arm rotates, about 180°, as it moves the valve control arm, the 3mm bolt will thread or unthread about 1/2 a revolution, and move up and down .25mm which shouldn't be a problem.   I'm going to start with a 9" long straight piece of 9 AWG wire and bend it a little long, Then put a slight kink in it to match the servo/valve.   Starting at the welded bolt, the first bend 90° down will be 3" from the weld, enough to miss the mount board when the arm is to the right (valve closed).   The second bend 90° up will be under the 1/4" hole in the control arm.

Remember, as in all servo applications, you must be sure the servo is at a known point in it's rotation before attaching the activator arm, I centered all mine and installed the arm straight down when the servo was centerd.   The arms swing from left, dowm, and to the right or vise versa.   I set up a servo setting program in the control system so I could easily find and mark the program values for each servo postion (open, closed).   Once I have determined the open/close programmed value, I'll put that in the program's VlvOpnCls[][] array.  

When I manually started tool #8 (DW735 Planer), using the data terminal keypad, it worked great but when I connected Isnsr 8, and tried auto mode (start the planer's motor), the valve wouldn't open all the way.   I realized when you turn on the DW735 Planer (to autostart the DC) it's chip ejector blows so hard, out the dust port and into the updraft valve, the servo, trying to open the valve's flapper, was working against this force.   I'm going to have to do some testing to find out how much power I need to open this valve under pressure.   Possibly a tougher servo and longer horn or a completely new 4" slide valve.   Or think of a better way to do this!

The Servo

One of the MG996 servos with a actuator arm ("horn") installed.  



Another view.   This is more or less how it will be mounted.



A servo and it's mounting board.  



Mounted on it's board with a couple of 3mm x .5 x 10mm screws and nuts.   When I mounted this on an updraft valve I realized I needed to mount the servo's flanges below the mounting board to lower the horn (actuator arm).



Roll of 9 AWG steel wire from Lowes.  



Cutting off 9" segments of more or less straight wire.  



Wire segments with 3mm bolt (ugly)welded on the end.   Note the two black marks on the bottom piece, they are the first two bends.



Wire linkage bent and threadded onto a servo actuator arm (aka. horn).  



Heres one installed with it's bends.   Note how it bends down, goes under the valve control arm then back up through the new hole 1.3" from the pivot point of the control arm.   When the valve is at rest, in either position, you should be able to jiggle the lnikage without the contorl arm moving.   The 9AWG wire is .114" so I drilled a 1/4" hole in the control arm for it, so it could have a little play.   These updraft valves aren't like slider type blast gates where you have to jam them solidly shut or open.



And another installed on the 6" updraft valve.   This 6" updraft valve is larger than the others so I had to move the srvo mounting board down to miss the adjacent valve's control arm.   Also there would be more clearance if the down (counter clock in the pic) instead of up.  



Most linkages installed.  



Test Sketch
/*********************************************************************** 
Adafruit 16-channel PWM Servo driver PCA9685, 2004 LCD 
TOGGLE BETWEEN LEFT AND RIGHTD SERVO (180 deg.) ClOSED = ARM RIGHT
THIS SKETCH SHOULD WORK WITH EITHER THE ARDUINO DATA TERMINAL OR IDE
************************************************************************/
#include <Wire.h>
#include <Adafruit_PWMServoDriver.h>

/************************** DEFINES ************************************/
#define SERVOADDR  0X40                               // SECONDARY ADDR: 0X41
// SERVO FREQ: 50Hz = 20MS/cycl, 2MS / 4096 = 4.882 US/incr
#define SERVO_FREQ 50                   // ANALOG SERVOS RUN AT 50 Hz UPDATES
#define CLRDLY   200                              // CLEAR SCREEN DELAY 200MS
#define HI         1
#define LO         0
#define LEFT       160
#define RIGHT      480
#define SPLAT     '*'
#define NL         10
#define BS         8
#define SPC        32
#define ROWMAX     4
#define COLMAX     20
#define DSPDLY    500                                      // DISPLAY TIME Ms 
#define IDLE       0
#define MLEFT      1
#define MRIGHT     2
#define INSTRMAX 100
// #define DEBUG      1

/************************** VARIABLES ************************************/
Adafruit_PWMServoDriver Servo = Adafruit_PWMServoDriver( SERVOADDR );
short Left = LEFT, Right = RIGHT;
long NxtDspl = 0;                                 // NEXT TIME BUTTON DEBOUNCE
byte MinMax = 0;                                        // LEFT/RIGHT CONTROL
bool KeyAvail = false;
char InStr[INSTRMAX]; 
byte InNdx = 0, ChrNdx = 0, Mode = IDLE;
char PosCur[8] = { ESC,'[','0',';','0','0','f',0};// POSITION CURSOR, ROW,COL
char ClrScrn[6] = { ESC,'[','2','j',0};        

/************************** PROTOTYPES ************************************/
void srvoLft( uint8_t num);
void srvoRt( uint8_t num);
char getChr();
void cancel();
void posCur( byte row, byte col );

/*F******************************************************************
*
**********************************************************************/
void 
setup() 
{
    Serial.begin( 9600 );
    Serial.print( "    Servo Test");
    Servo.begin();
    Servo.setPWMFreq( SERVO_FREQ );    // ANALOG SERVOS RUN AT ~50 Hz UPDATES
    NxtDspl = millis() + DSPDLY;                              // CAPTURE TIME
    memset( InStr, 0, sizeof( InStr ));                    // CLEAR ASCII BUF
    delay( 500 );
}
/*F******************************************************************
*
**********************************************************************/
void 
loop() 
{
    long   now;
    char   chr;

    if( KeyAvail )
    {
        chr = getChr();
        switch( chr )
        {
            case '0':                            // CANCEL CURRENT OPERATION
                cancel();
                break;
            case '4':                           // LEFT MODE
                Mode = LEFT;
                posCur( 2, 0);
                Serial.print( "Left: " );
                break;
            case '6':                           // RIGHT MODE
                Mode = RIGHT;
                posCur( 2, 0);
                Serial.print( "Right: " );
                break;
            case '2':                           // INCREMENT SERVO VALUE
                if( Mode = MLEFT )
                    Left += 5;
                else if( Mode = MRIGHT )
                    Right += 5;
                srvoLft( 1 );
                break;
            case '8':                           // DECREMENT SERVO VALUE
                if( Mode = MLEFT )
                    Left -= 5;
                else if( Mode = MRIGHT )
                    Right -= 5;
                srvoRt( 1 );
                break;
        }
    }
    now = millis();
    if( now > NxtDspl )
    { 
        NxtDspl = millis() + DSPDLY;                          // CAPTURE TIME
        switch( Mode )
        {
            case  IDLE:
                return;
            case MRIGHT:
                posCur( 1, 9 );
                Serial.print( Right );
                srvoRt( 1 );
                break;
            case MLEFT:
                posCur( 1, 9 );
                Serial.print( Left );
                srvoLft( 1 );
                break;
        }
    }
    delay( 500 );                       // WAIT 1/2 SEC
}
/*F******************************************************************
* GET CHAR FROM INSTR
**********************************************************************/
char
getChr()
{                                         // RUNS EACH TIME (AFTER) LOOP RUNS
    char   chr;

    if( (KeyAvail != true) || (InNdx == 0) )
        return( 0 );
    if( ChrNdx < InNdx )
    {
        chr = InStr[ChrNdx];
        InStr[ChrNdx++] =0;
        return( chr );
    }
    KeyAvail = false;
    InNdx = ChrNdx =0;
    return( 0 );
}
/*F******************************************************************
* CANCEL CURRENT OPERATION
**********************************************************************/
void
cancel()
{   
    Mode = IDLE;
}
/*F*******************************************************************
*
**********************************************************************/
void
srvoRt( uint8_t num)
{
    int    val;

    val = Right;
    posCur( 1, 10 ); 
    Serial.print((String)"Right " + ", val = " + val);
    Servo.setPWM( num, 0, val);
    delay( 100 );
}
/*F*******************************************************************
*
**********************************************************************/
void
srvoLft( uint8_t num)
{
    int    val;

    val = Left;
    posCur( 0, 2 ); 
    Serial.print("Left, val = " + (val +0x30) );
    Servo.setPWM( num, 0, val);
    delay( 100 );
}
/*F******************************************************************
* RS-232 INTERRUPT SERVICE ROUTINE, DO NOT TARRY HERE
**********************************************************************/
void
serialEvent()
{                                         // RUNS EACH TIME (AFTER) LOOP RUNS
    char  chr;

    while( Serial.available()) // INTERRUPT SERVICE ROUTINE, DON'T TARRY HERE
    {
        chr = (char)Serial.read();                            // GET NEW CHAR
        if( (chr != NL) && (chr < 32) )
            continue;                           // DISCARD NON_PRINTABLE CHAR
        InStr[InNdx++] = chr;                      // ADD NEW CHAR TO InStr[]
        KeyAvail = true;         // SET FLAG SO MAIN LOOP CAN DO PROCESS CHAR
        if( InNdx >= INSTRMAX )
        {                                   // IN STR NDX TOO LARGE, RESET IT
            InNdx =0;
            break;
        }
    }
}
/*F******************************************************************
* POSITION CURSOR Esc[r;ccf   SET CURSOR TO ROW COL
**********************************************************************/
void
posCur( byte row, byte col )
{
    char    str[8];

    strcpy( str, PosCur );
    sprintf( &str[2], "%1d;%02df", row, col );
    Serial.print( str );
    delayMicroseconds( 200 );
}