SALES INQUIRIES: 1 (888) 767-9864

Arduino in Industry :: Student Project

Imagine for a moment you are an experienced engineer technician at a power plant and you need to train up and coming techs on how to operate different work stations.

While you can talk people through the operation of critical tasks, until you actually do the task, well, it’s kind of tough to get a handle on it.

Why not simulate it?

That is exactly what Jim Greever did.

Check out this Control Rod Simulator that Jim created with an Arduino Mega and lots of cool gauges!

Pictures:

back

The heart of the simulator is an Arduino Mega (Above).

close-up

Jim used copper tape on several connections (Above).  Jim says soldering to the copper tape is pretty easy, you just have to make sure t doesn’t get too hot.

From the simulator manual Arduino Mega controlled

This is from a page of the simulators documentation that Jim wrote.  You can download the whole manual below – it’s pretty cool!

Jim says of this simulator:

We use this in our class, it was intended to give students a chance to simulate operation prior to performing on the actual unit.

Arduino Code:

Jim was kind enough to share his code…

/*
  Using the MP E-41.2, this program is to mimic a real function test.
  This is a working version, it works with procedure.
*/
#include <Servo.h>
#include <Wire.h>
#include "Adafruit_LEDBackpack.h"
#include "Adafruit_GFX.h"
Adafruit_7segment matrix = Adafruit_7segment();
#include "Arduino.h"

// the following sets the varibles and pin locations
int SyncStateCount;
int newpos;
Servo GenVolts1;
Servo ACAmps1;
Servo GenAmpsOut1;
int Gen1Close = LOW;
const int numReadings = 20;
int readings; // the readings from the analog input
int readIndex = 0; // the index of the current reading
int total = 0; // the running total
int average = 0;
int value;
int pos = 50;
int pos1;
int cal;
int trip;
int once;
const int VoltKnob1 = A0;
int VoltSet1;
const int Exciter1 = 53;
int ExciterState1;

int ExciterCurrentState1;
int ExciterOn;
const int Sync1 = 11;
int SyncState1;
int ToggleState1;
int Repeat = HIGH;
int RanOnce;
const int Mg1Bkr = 42;
const int Mg1BkrT = 40;
int Mg1BkrState;
int Mg1BkrStateT;
int Mg1BkrCurrentState;
int Mg1RUNState;
int Mg1STOPState;
const int Gen1Bkr = 47;
const int Gen1BkrT = 45;
int Gen1BkrState;
int Gen1BkrStateT;
int Gen1BkrCurrentState;
int Gen1OPENState;
int Gen1CLOSEState;
const int MgRed1 = 38;

const int MgGrn1 = 36;
const int GenRed1 = 51;
const int GenGrn1 = 49;
Servo GenVolts2;
Servo ACAmps2;
Servo GenAmpsOut2;

// all of this stuff used to help stablize analog input
const int numReadings2 = 20;
int readings2 ; // the readings from the analog input
int readIndex2 = 0; // the index of the current reading
int total2 = 0; // the running total
int average2 = 0;
int value2;
int pos2 = 50;
int pos21;
int cal2;
int trip2;
int once2;

// start naming all the devices
const int VoltKnob2 = A1;
int VoltSet2;

const int Exciter2 = 43;
int ExciterState2;
int ExciterCurrentState2;
int ExciterOn2;

const int Sync2 = 10;
int SyncState2;
int ToggleState2;
int Repeat2 = HIGH;
int RanOnce2;

const int Mg2Bkr = 22;
const int Mg2BkrT = 24;

int Mg2BkrState;
int Mg2BkrStateT;
int Mg2BkrCurrentState;
int Mg2RUNState;
int Mg2STOPState;

const int Gen2Bkr = 37;
const int Gen2BkrT = 35;

int Gen2BkrState;
int Gen2BkrStateT;
int Gen2BkrCurrentState;
int Gen2OPENState;
int Gen2CLOSEState;

const int MgRed2 = 26;
const int MgGrn2 = 28;
const int GenRed2 = 41;
const int GenGrn2 = 39;

// ================== Main SETUP ==============================
void setup() {
  
  // setting the 7 segment display to OFF
  matrix.begin(0x75); // A0, A2 jumpered
  matrix.clear();
  matrix.setBrightness (0);
  matrix.writeDisplay();

  matrix.begin(0x70);
  matrix.clear();
  matrix.setBrightness (0);
  matrix.writeDisplay();

  // switches and buttons
  pinMode(Exciter1, INPUT_PULLUP);
  pinMode(Sync1, INPUT_PULLUP);
  pinMode(Mg1Bkr, INPUT_PULLUP);
  pinMode(Mg1BkrT, INPUT_PULLUP);
  pinMode(Gen1Bkr, INPUT_PULLUP);
  pinMode(Gen1BkrT, INPUT_PULLUP);
  pinMode(Exciter2, INPUT_PULLUP);
  pinMode(Sync2, INPUT_PULLUP);
  pinMode(Mg2Bkr, INPUT_PULLUP);
  pinMode(Gen2Bkr, INPUT_PULLUP);
  pinMode(Mg2BkrT, INPUT_PULLUP);
  pinMode(Gen2BkrT, INPUT_PULLUP);

  // leds
  pinMode(MgRed1, OUTPUT);
  pinMode(MgGrn1, OUTPUT);
  pinMode(GenRed1, OUTPUT);
  pinMode(GenGrn1, OUTPUT);
  pinMode(MgRed2, OUTPUT);
  pinMode(MgGrn2, OUTPUT);
  pinMode(GenRed2, OUTPUT);
  pinMode(GenGrn2, OUTPUT);

  GenVolts1.attach(5);
  ACAmps1.attach(6);
  GenAmpsOut1.attach(7);
  GenVolts2.attach(2);
  ACAmps2.attach(3);
  GenAmpsOut2.attach(4);

  // set all the servos to move to indicate 0
  GenVolts1.write(180);
  ACAmps1.write(180);
  GenAmpsOut1.write(180);
  GenVolts2.write(180);
  ACAmps2.write(180);
  GenAmpsOut2.write(180);
  delay (15);

  // set all the OPEN/TRIP leds to ON
  digitalWrite(GenGrn1, HIGH);
  digitalWrite(MgGrn1, HIGH);
  digitalWrite(GenGrn2, HIGH);
  digitalWrite(MgGrn2, HIGH);
  
} // end void setup


// =============Main Loop and IF statements=====================

void loop() {
  Mg1BkrState = digitalRead (Mg1Bkr); // read switch position LOW = ON, HIGH = OFF
  Mg1BkrStateT = digitalRead(Mg1BkrT);
  Gen1BkrState = digitalRead (Gen1Bkr);
  Gen1BkrStateT = digitalRead (Gen1BkrT);
  SyncState1 = digitalRead(Sync1); // will be used later to parallel both MGs.
  Mg2BkrState = digitalRead (Mg2Bkr); // read switch position LOW = ON, HIGH = OFF
  Mg2BkrStateT = digitalRead(Mg2BkrT);
  Gen2BkrState = digitalRead (Gen2Bkr);
  Gen2BkrStateT = digitalRead(Gen2BkrStateT);
  SyncState2 = digitalRead(Sync2); // will be used later to parallel both MGs.

  if (Mg2BkrState == LOW || Mg2RUNState == HIGH) {
    Mg2Run();
  }
  if (Mg2BkrStateT == LOW && Mg2RUNState == HIGH) {
    Mg2RUNState = LOW;
    Mg2STOPState = HIGH;
    Mg2Stop();
  }
  if (Mg1BkrState == LOW || Mg1RUNState == HIGH) {
    Mg1Run();
  }
  if (Mg1BkrStateT == LOW && Mg1RUNState == HIGH ) {
    Mg1RUNState = LOW;
    Mg1STOPState = HIGH;
    Mg1Stop();
  }
  if (Gen2BkrState == LOW && Mg2RUNState == HIGH) {
    Gen2OutBkrCls ();
  }
  if (Gen1BkrState == LOW && Mg1RUNState == HIGH ) {
    Gen1OutBkrCls ();
  }

  if (Gen1CLOSEState == HIGH && SyncState2 == LOW) {
    delay (9000);
    Gen2OutBkrCls ();
  }
  if (Gen2CLOSEState == HIGH && SyncState1 == LOW) {
    delay (9000);
    Gen1OutBkrCls ();
  }
  delay (10);
} // end Main Loop


void Mg1Run() {
  Mg1RUNState = HIGH;
  if (Mg1RUNState == HIGH ) {
    digitalWrite(MgGrn1, LOW);
    digitalWrite(MgRed1, HIGH);
    ExciterState1 = digitalRead(Exciter1);
    if (ExciterState1 == LOW || ExciterOn == HIGH ) {
      ExciterOn = HIGH; // helps keep in loop
      // this section to help stablize analog readings
      total = total - readings;
      readings = analogRead(VoltKnob1);
      total = total + readings;
      readIndex = readIndex + 1;
      if (readIndex >= numReadings) {
        readIndex = 0;
      }
      average = total / numReadings;
      // mapping to define servo movement that concides with Volts adjustment
      pos = map (average, 1023, 0, 1, 60);
      GenVolts1.write(pos);
      // mapping to define servo movement, part from POS/Volt meter
      pos1 = map (pos, 100, 30, 160, 122);

      ACAmps1.write(pos1);
      if ( Gen1CLOSEState == HIGH) {
        cal = map (pos, 100, 30, 10, 70);
        matrix.begin(0x75); // A0, A2 jumpered
        matrix.print(cal, DEC);
        matrix.setBrightness (2);
        matrix.writeDisplay();
        if (pos < 15 || pos > 50) {
          Gen1OutBkrOpn();
        }
      }
    } // end if EXCITER field
    RanOnce = LOW;
  } // end if MG1Run = HIGH
} // end Mg1Run

void Mg1Stop () {
  if (Mg1STOPState == HIGH ) {
    Mg1BkrCurrentState = Mg1BkrState;
    digitalWrite(MgRed1, LOW);
    digitalWrite(MgGrn1, HIGH);
    digitalWrite(GenRed1, LOW);
    digitalWrite(GenGrn1, HIGH);
    matrix.begin(0x75); // A0, A2 jumpered
    matrix.clear();
    matrix.setBrightness (0);
    matrix.writeDisplay();
    // set all the meters to zero
    for (pos1; pos1 < 180; pos1 += 1) {
      GenVolts1.write(pos1);
      ACAmps1.write(pos1);
      delay(15);
    }
    GenAmpsOut1.write(180);
    ExciterOn = LOW;
    RanOnce = HIGH;
  }
}

void Mg2Run() {
  Mg2RUNState = HIGH;
  if (Mg2RUNState == HIGH) {
    trip2 = LOW;
    digitalWrite(MgGrn2, LOW);
    digitalWrite(MgRed2, HIGH);
    ExciterState2 = digitalRead(Exciter2);
    if (ExciterState2 == LOW || ExciterOn2 == HIGH) {
      ExciterOn2 = HIGH;
      total2 = total2 - readings2;
      readings2 = analogRead(VoltKnob2);
      total2 = total2 + readings2;
      readIndex2 = readIndex2 + 1;
      if (readIndex2 >= numReadings2) {
        readIndex2 = 0;
      }
      average2 = total2 / numReadings2;
      // mapping to define servo movement that concides with Volts adjustment
      pos21 = map (average2, 1023, 0, 1, 60);
      GenVolts2.write(pos21);
      pos2 = map (pos21, 100, 30, 160, 122);
      ACAmps2.write(pos2);

      if (Gen2CLOSEState == HIGH) {
        cal2 = map (pos21, 100, 30, 10, 70);
        matrix.begin(0x70);
        matrix.print(cal2, DEC);
        matrix.setBrightness (2);
        matrix.writeDisplay();
        if (pos21 < 20 || pos21 > 50) {
          Gen2OutBkrOpn();
        }
      }
      RanOnce2 = LOW;
    }
  }
}

void Mg2Stop() {
  if (Mg2STOPState == HIGH) {
    Mg2BkrCurrentState = Mg2BkrState;
    digitalWrite(MgRed2, LOW);
    digitalWrite(MgGrn2, HIGH);
    digitalWrite(GenRed2, LOW);
    digitalWrite(GenGrn2, HIGH);
    matrix.begin(0x70);
    matrix.clear();
    matrix.setBrightness (0);
    matrix.writeDisplay();
    for (int pos21; pos21 < 180; pos21 += 1)
    {
      GenVolts2.write(pos21);
      ACAmps2.write(pos21);
      delay(15);
    }
    GenAmpsOut2.write(180);
    ExciterOn2 = LOW;
    RanOnce2 = HIGH;
  }
}

void Gen1OutBkrCls() {
  Gen1CLOSEState = HIGH;
  if (Gen1CLOSEState == HIGH) {
    digitalWrite(GenGrn1, LOW);
    digitalWrite(GenRed1, HIGH);
    if (Mg1RUNState == HIGH && ExciterOn == HIGH) {
      GenAmpsOut1.write(160);
      delay (100);
    }
    Gen1Close = HIGH;
  }
}

void Gen2OutBkrCls() {
  Gen2CLOSEState = HIGH;
  if (Gen2CLOSEState == HIGH) {
    digitalWrite(GenGrn2, LOW);
    digitalWrite(GenRed2, HIGH);
    if (Mg2RUNState == HIGH && ExciterOn2 == HIGH) {
      GenAmpsOut2.write(160);
      delay(100);
    }
  }
}

void Gen2OutBkrOpn() {
  Gen2CLOSEState = LOW;
  Gen2OPENState = HIGH;
  if (Gen2OPENState == HIGH) {
    trip2 = HIGH; // used as a condition for closing breaker
    later.
    digitalWrite(GenRed2, LOW);
    digitalWrite(GenGrn2, HIGH);
    GenAmpsOut2.write(180);
    delay (15);
  }
}

void Gen1OutBkrOpn() {
  Gen1CLOSEState = LOW;
  Gen1OPENState = HIGH;
  if (Gen1OPENState == HIGH) {
    trip = HIGH; // used as a condition for closing breaker later.
    digitalWrite(GenRed1, LOW);
    digitalWrite(GenGrn1, HIGH);
    GenAmpsOut1.write(180);
    delay (15);
  }
}

 

The Documentation:

You can dowload the operation manual for the simulator here. It is a pretty neat read.

Control Rod Drive MG Simulator

Jim has been a long time student at programming electronics academy, a wonderful contributor and as always continues to amaze me.

Thank for sharing this Jim!

2 Comments

  1. Avatar JohnnyFRX on September 27, 2016 at 10:03 am

    WOW! I used to work in a Lab environment and would frequently deal with the Facilities Maintenance Dept. Your training lab here looks pretty much like the real deal. Nice Work Man!

    • Avatar MICHAEL JAMES on September 27, 2016 at 12:31 pm

      I agree with Johnny, Jim did a great job with this.

Leave a Comment