Compare commits

...

2 Commits

Author SHA1 Message Date
a4e129a3e3 Updated TOC for readme 2025-01-16 21:09:06 -06:00
5d41a6bf40 Actuator box code in readme 2025-01-16 21:08:21 -06:00

318
README.md
View File

@ -1,3 +1,4 @@
# Table of Conents
- [Purpose](#purpose)
- [Overall System Design](#overall-system-design)
* [Concept of Operation](#concept-of-operation)
@ -39,6 +40,11 @@
- [Latching Relay Display](#latching-relay-display)
- [Latching Solenoid Display](#latching-solenoid-display)
* [Actuator Box](#actuator-box-2)
+ [Logic Diagram](#logic-diagram-3)
+ [Custom Relay Control Classes](#custom-relay-control-classes)
- [Non-Latching Relay Class](#non-latching-relay-class)
- [Latching Relay Class](#latching-relay-class)
- [Latching Solenoid Class](#latching-solenoid-class)
- [System Upgrades After Initial Design](#system-upgrades-after-initial-design)
* [Servo Motor Main Valve for Throttling](#servo-motor-main-valve-for-throttling)
* [MODBUS TCP Communication for Integration in Ignition SCADA](#modbus-tcp-communication-for-integration-in-ignition-scada)
@ -126,7 +132,7 @@ The actuator box is responsible for actuating valves on the oxidizer fluid panel
# Arduino Software
## Common Software
### CAN Comms
For the peer to peer communication between the Control Box and the Actuator Box, the Controller Area Network (CAN) Bus was chosen for its amazing signal integrity and simple to use libraries with Arduino. Key features in this use case are the 8 byte frames sending unsigned chars and the can_id unsigned integer which designates the type of packet being sent.
For the peer to peer communication between the control box and the actuator box, the Controller Area Network (CAN) Bus was chosen for its amazing signal integrity and simple to use libraries with Arduino. Key features in this use case are the 8 byte frames sending unsigned chars and the can_id unsigned integer which designates the type of packet being sent.
On startup (and communication loss from a power outage, random restart, or CAN harness disconnect), the devices go through a 2-way handshake that consists of the control box sending a ping, the actuator box replying to the ping, and the control box acknowledging the reply.
@ -301,8 +307,316 @@ class LatchingSolenoidDisplays {
```
## Actuator Box
### Logic Diagram
There currently is no logic diagram for the actuator box.
### Custom Relay Control Classes
The actuator box features digital pin failure detection and relay failure detection. It accomplishes this through a spare digital pin set as an input to monitor the output pin, as well as a analog input to measure the relay contacts' status.
In addition to failure detection, it is important for anything latching to send as short as possible pulses to set and reset the latch. For the latching relays and latching solenoids, the system monitors how long it takes to set or reset and automatically turns off based on rising and falling edge rather than simple pulse duration.
#### Non-Latching Relay Class
```cpp
class NonLatchingRelay {
private:
String name = "Non-Latching Relay";
unsigned int pin;
unsigned int pin_readback;
// The desired state of the pin
bool pin_desired_state;
// The actual state of the pin per the readback
bool pin_actual_state;
bool pin_working;
unsigned int voltage_read_pin;
// The desired state of the relay, set by the control program
bool desired_state = false;
// The expected state of the relay based off of digital spin readback
bool expected_state;
// Whether or not there actually is a voltage across the relay or not
bool actual_state;
bool relay_working;
// This is used so that the object knows whether or not to use the normal or startup function to control
bool startup = true;
// The max time in ms that we would expect the Arduino to see a voltage change across the relay after turning on the pin
const unsigned long relay_delay = 500;
// The millis() that the relay was turned on. Useful for knowing if it is operating correctly
unsigned long relay_turned_on_time;
// The millis() that the relay was turned off. Useful for knowing if it is operating correctly
unsigned long relay_turned_off_time ;
// The millis() that we first saw a voltage across the relay after trying to turn it on
unsigned long relay_first_voltage_time;
// The millis() that we first saw no voltage across the relay after trying to turn it off
unsigned long relay_first_no_voltage_time;
// How many times we should read the relay voltage and average
const unsigned int num_voltage_reads = 3;
// Get a single voltag reading across the relay
float read_relay_voltage();
// Average a few voltage readings and determine if the relay has ~12V across it
void update_actual_state();
void update_if_pin_working();
void update_if_relay_working();
void turn_on_relay();
void turn_off_relay();
// Turns on relay as well as setting values that may have been uninitialized
void turn_on_relay_startup();
// Turns off relay as well as setting values that may have been uninitialized
void turn_off_relay_startup();
public:
NonLatchingRelay(String name,
unsigned int pin,
unsigned int pin_readback,
unsigned int voltage_read_pin);
NonLatchingRelay(unsigned int pin,
unsigned int pin_readback,
unsigned int voltage_read_pin);
// Gets the state of the pin_working
bool get_pin_working() const {return pin_working;}
// Gets the desired state of the relay
bool get_desired_state() const {return desired_state;}
// Gets the expected state of the relay
bool get_expected_state() const {return expected_state;}
// Gets the actual state of the relay
bool get_actual_state() const {return actual_state;}
// Gets whether or not the relay is working correctly
bool get_relay_working() const {return relay_working;}
// Gets the time that the first voltage was seen after trying to turn on
unsigned long get_relay_first_voltage_time() const {return relay_first_voltage_time;}
// Gets the time that the first no voltage was seen after trying to turn off
unsigned long get_relay_first_no_voltage_time() const {return relay_first_no_voltage_time;}
// Set the desired state of the relay
void set_desired_state(unsigned char new_desired_state);
// Controls the relay including pins to get relay to desired state, checking if the pin needs to be turned off, and error detection
void control_relay();
};
```
#### Latching Relay Class
```cpp
class LatchingRelay {
private:
String name = "Latching Relay";
unsigned int setpin;
unsigned int setpin_readback;
// What we are telling the pin to be (HIGH vs LOW)
bool setpin_desired_state = false;
// The current state of the setpin as per the readback
bool setpin_actual_state;
bool setpin_working;
unsigned int resetpin;
unsigned int resetpin_readback;
// What we are telling the pin to be (HIGH vs LOW)
bool resetpin_desired_state = false;
// The current state of the resetpin
bool resetpin_actual_state;
bool resetpin_working;
unsigned int voltage_read_pin;
// The time in ms that the coil should stay on AFTER seeing a voltage change
const unsigned long extra_pin_duration = 100;
// The millis() that the setpin was turned on
unsigned long setpin_turned_on_time;
// The millis() that the resetpin was turned on
unsigned long resetpin_turned_on_time;
// The desired state of the relay, set by the control program
bool desired_state = false;
// The expected state of the relay based off of digital setpin and resetpin readbacks
bool expected_state;
// Whether or not there actually is a voltage across the relay or not
bool actual_state;
bool relay_working;
// This is used so that the object knows whether or not to use the normal or startup function to control
bool startup = true;
// The max time in ms that we would expect the Arduino to see a voltage change across the relay after turning on the pin
const unsigned long relay_delay = 500;
// The millis() that the relay was turned on. Useful for knowing if it is operating correctly
unsigned long relay_turned_on_time;
// The millis() that the relay was turned off. Useful for knowing if it is operating correctly
unsigned long relay_turned_off_time;
// The millis() that we first saw a voltage across the relay after trying to turn it on
unsigned long relay_first_voltage_time;
// The millis() that we first saw no voltage across the relay after trying to turn it off
unsigned long relay_first_no_voltage_time;
// How many times we should read the relay voltage and average
const unsigned int num_voltage_reads = 3;
// Get a single voltag reading across the relay
float read_relay_voltage();
// Average a few voltage readings and determine if the relay has ~12V across it
void update_actual_state();
// Perform a check to see if the pins are working based on readbacks
void update_if_pins_working();
// Check if the relay is working based on expected vs actual state
void update_if_relay_working();
// Turn the pins off after the appropriate time
void turn_off_pins_after_duration();
void turn_on_relay();
void turn_off_relay();
// Turns on relay as well as setting values that may have been uninitialized
void turn_on_relay_startup();
// Turns off relay as well as setting values that may have been uninitialized
void turn_off_relay_startup();
// Only called when the expected state != actual state due to some unkown failure (vibration, transistor for some reason turning on, etc)
void turn_on_relay_from_fail();
// Only called when the expected state != actual state due to some unkown failure (vibration, transistor for some reason turning on, etc)
void turn_off_relay_from_fail();
public:
LatchingRelay(String name,
unsigned int setpin,
unsigned int setpin_readback,
unsigned int resetpin,
unsigned int resetpin_readback,
unsigned int voltage_read_pin);
LatchingRelay(unsigned int setpin,
unsigned int setpin_readback,
unsigned int resetpin,
unsigned int resetpin_readback,
unsigned int voltage_read_pin);
bool get_setpin_working() const {return setpin_working;}
bool get_resetpin_working() const {return resetpin_working;}
bool get_desired_state() const {return desired_state;}
bool get_expected_state() const {return expected_state;}
bool get_actual_state() const {return actual_state;}
bool get_relay_working() const {return relay_working;}
// Set the desired state of the relay
void set_desired_state(unsigned char new_desired_state);
// Controls the relay including pins to get relay to desired state, checking if pins need to be turned off, and error detection
void control_relay();
};
```
#### Latching Solenoid Class
```cpp
class LatchingSolenoid {
private:
String name = "Latching Solenoid";
unsigned int onpin;
unsigned int onpin_readback;
bool onpin_working;
unsigned int offpin;
unsigned int offpin_readback;
bool offpin_working;
unsigned int on_voltage_read_pin;
unsigned int off_voltage_read_pin;
// The millis() time that we first saw a voltage across
unsigned long on_relay_first_voltage_time;
// The millis() time that we first saw a voltage across
unsigned long off_relay_first_voltage_time;
// How many ms the relay should be turned on to move the solenoid position
const unsigned long set_duration = 1000;
// We want to see at least this long to assume the solenoid turned on
const unsigned long set_duration_minimum = 100;
// The current state of the on relay
bool on_relay_actual_state;
bool on_relay_working;
// The current state of the off relay
bool off_relay_actual_state;
bool off_relay_working;
// The desired state of the solenoid, set by the control program
bool desired_state = false;
// The expected state of the solenoid based off of voltage readbacks across the relays
bool expected_state;
// This is used so that the object knows whether or not to use the normal or startup function to control
bool startup = true;
NonLatchingRelay on_relay;
NonLatchingRelay off_relay;
void update_first_voltage_times();
void update_relay_actual_states();
void update_if_pins_working();
void update_if_relays_working();
void update_solenoid_expected_state();
void turn_off_relays_after_duration();
void turn_on_solenoid();
void turn_off_solenoid();
void turn_on_solenoid_startup();
void turn_off_solenoid_startup();
public:
LatchingSolenoid(String name,
unsigned int onpin,
unsigned int onpin_readback,
unsigned int offpin,
unsigned int offpin_readback,
unsigned int on_voltage_read_pin,
unsigned int off_voltage_read_pin);
LatchingSolenoid(unsigned int onpin,
unsigned int onpin_readback,
unsigned int offpin,
unsigned int offpin_readback,
unsigned int on_voltage_read_pin,
unsigned int off_voltage_read_pin);
bool get_onpin_working() const {return onpin_working;}
bool get_offpin_working() const {return offpin_working;}
bool get_on_relay_actual_state() const {return on_relay_actual_state;}
bool get_off_relay_actual_state() const {return off_relay_actual_state;}
bool get_desired_state() const {return desired_state;}
bool get_expected_state() const {return expected_state;}
bool get_on_relay_working() const {return on_relay_working;}
bool get_off_relay_working() const {return off_relay_working;}
void set_desired_solenoid_state(unsigned char new_desired_state);
void control_solenoid();
};
```
# System Upgrades After Initial Design
## Servo Motor Main Valve for Throttling
The BVAS (ball valve actuator system) that uses 2 solenoids to control a pneumatic valve for the main oxidizer valve for the engine lacks throttlability and other nice to have features. The team shifted towards using a servo motor controller via PWM (pulse width modulation) to give us more granular control of the mass flow rate of oxidizer.
## MODBUS TCP Communication for Integration in Ignition SCADA
Because the actuator box has the expansion ports setup, a jumper cable was connected to a panel mount and commands the servo. In the code, one can either set pre-determined values for the servo angles or define a function of time to control the servo angle.
## MODBUS TCP Communication for Integration in Ignition SCADA
Not included in the code in this repository, but MODBUS TCP was integrated into the actuator box using the W5500 ethernet module so that it can more easily tie into Ignition SCADA (supervisory control and data acquisition). The shift to Ignition came with adding off the shelf PLCs to our control stack and other equipment.
The actuator box acts as a MODBUS server and has coils setup for each relay as well as input registers for all of the different status and fail bits. There is also a holding register setup for the servo motor control.