Introduction: Remote Controlled Pneumatic Cylinder

The goal of this project is to control a solenoid connected to a pneumatic cylinder remotely via RF transmission. The potential uses of such a system are many, but I designed this one with theatrical prop. effects in mind.

This system relies on two Arduino UNOs which communicate with each other wirelessly via nrf24l01 wireless modules operating in the 2.4GHz range. These modules use the Radiohead library and can act as transmitter, receiver, or transceiver. In this project, the "client" Arduino sends a signal to the "server" Arduino, which then triggers a solenoid to release air into a double-acting pneumatic cylinder. The code can be easily manipulated for a variety of different effects.

Step 1: What You'll Need

I've included links to many of the specific items I used, but there are many other options out there.

Pneumatic Setup

Arduino Setup

  • Arduino UNO (2) nrf24l01 2.4GHz wireless module (2)
  • Socket adaptor plate (8 pin) for nrf24l01 module
  • Momentary button
  • 10kΩ resistor (2)
  • TIP120 Darlington Transistor
  • Rectifier diode (1N4001)
  • Jumper wires
  • Breadboards or PCBs (2)
  • 9v battery connector and battery (powers “client” Arduino)
  • 12v Rechargeable Battery Pack (powers “server” Arduino and solenoid) https://www.amazon.com/gp/product/B01M7Z9Z1N/ref=...

Step 2: Pneumatic Setup

To supply air to the solenoid, I used a 1.5gal. air tank (the type used for air horns). On one end, it is fitting with a filling valve and male connector. On the other, it has a tank output valve in line with a regulator. For this particular cylinder, I found that between 30-40psi coming through the regulator did the trick.

Step 3: The Solenoid

I chose to use a 5 port, 2 way, 12v solenoid. Because it runs on 12v, it is able to share a power supply with the Arduino and pull 12v power from the Arduino's VIN pin. My solenoid had 1/8" NPT connections, but there are also 1/4" varieties available. The 3 ports on the left are the air input, in between the two exhaust ports. I left the exhaust ports empty, but you could gain more functionality by adding mufflers, flow control valves, or both.

Step 4: Arduino # 1 "Client"

The code for both Arduinos is derived from sample sketches included with the Radiohead library. The Radiohead library makes it much easier to integrate the nrf24l01 tranceiver modules on both sides. The "client" side of the system essentially does the following:

1) Set up matching transmit/receive settings with the "server" Arduino.

2) Initialize RF contact (and send an error message via serial monitor if contact fails)

3) Look for a button press (digital I/O pin 2)

4) If button is pressed, send a message to the "server" Arduino.

*Don't forget that the momentary button needs a pull-down resistor on the ground side. I used 10kΩ.

Step 5: Arduino "Client" Code

// nrf24_client<br>
/*
NRF24L01      Arduino
CE       >     D8
CSN      >     D10
SCK      >     D13
MO       >     D11
MI       >     D12
RO       >     Not used 
GND      >     GND
VCC      >     5V
 */
#include <SPI.h>
#include <RH_NRF24.h>
const int button = 2;
// Singleton instance of the radio driver
RH_NRF24 nrf24;
void setup() 
{
  Serial.begin(9600);
  if (!nrf24.init())
    Serial.println("init failed");
  // Defaults after init are 2.402 GHz (channel 2), 2Mbps, 0dBm
  if (!nrf24.setChannel(125))
    Serial.println("setChannel failed");
  if (!nrf24.setRF(RH_NRF24::DataRate2Mbps, RH_NRF24::TransmitPower0dBm))
    Serial.println("setRF failed");    
}
void loop()
{
  if (digitalRead(button) == HIGH)
  {
  uint8_t data[] = "104";
  nrf24.send(data, sizeof(data));
  }
  delay(50); //prevents data overflow when button is held (theoretically)
}

Step 6: Arduino "Server" Setup

The "Server" side of the system is identical to the "client" in the way the nrf24l01 is wired. The difference is that this Arduino is meant to receive the signal and perform an action. Here's what it does in this case:

1) Set up matching transmit/receive settings with the "client" Arduino.

2) Initialize RF contact (and send an error message via serial monitor if contact fails)

3) Define expectations for the type of message it will receive

4) Start a loop counter (1000 loops)

5) Look for a specific message

6) If the message ("104") is received, fire the solenoid and then retract it (using digital I/O pin 3). Reset counter

7) Otherwise, continue looking for the message and keep the solenoid retracted in the meantime.

This setup uses a TIP120 Darlington transistor to send 12v the solenoid when the pin fires. A 12v LiIon battery pack is used to power both the Arduino (via barrel plug) and the solenoid (via VIN pin). *Be careful not to connect anything else to the VIN pin, since it carries 12v and will damage most other components*

*Also remember to place a resistor (I used 10kΩ) in line with the "base" pin of the transistor to prevent higher voltages from running into the Arduino via the control line to pin 3.

As with all solenoids, this one requires a snubber diode to prevent transient voltage from running through the system once the solenoid has fired. The diode is directional and should run from the negative side of the coil to the positive side.

Step 7: Arduino "Server" Code

// nrf24_server
/*
NRF24L01      Arduino
CE       >     D8
CSN      >     D10
SCK      >     D13
MO       >     D11
MI       >     D12
RO       >     Not used 
GND      >     GND
VCC      >     5V
 */
#include <SPI.h>
#include <RH_NRF24.h>
const int FIRE = 3;
int timeOUT = 0;
RH_NRF24 nrf24;
void setup()
{
  pinMode(FIRE, OUTPUT);
  Serial.begin(9600);
  if (!nrf24.init())
    Serial.println("init failed");
  if (!nrf24.setChannel(125))           //set channel to 125
    Serial.println("setChannel failed");
  if (!nrf24.setRF(RH_NRF24::DataRate2Mbps, RH_NRF24::TransmitPower0dBm))
    Serial.println("setRF failed");
}
void loop()
{
  if (nrf24.available())
  {
    uint8_t buf[RH_NRF24_MAX_MESSAGE_LEN];   
    uint8_t len = sizeof(buf);
    if (nrf24.recv(buf, &len))             //read message
    {
      Serial.print("got request: ");
      Serial.println((char*)buf);
      int sig = atoi((const char*) buf);
      if (sig == 104)
      {
      digitalWrite(FIRE, HIGH);          //fire solenoid
      timeOUT = 0;  //message received, reset counter
      delay(150);
      digitalWrite(FIRE, LOW);
    }
  }
  else
  {
    if (timeOUT > 1000)                //close solenoid if this loop has ran _ or more times
    {
      digitalWrite(FIRE, LOW);         //close solenoid
    }
    timeOUT++;                       //increment counter
  }
  }
}

Step 8: Fire Away!

Okay, so there are probably better ways to shake a can of soup...

Also, gaff tape is not a recommended mounting method for pneumatic cylinders...