Introduction: Small Scale Winch

I want to build a portable, wireless winch for use in the theatre for special effects. This is a small scale test to test wireless control and begin working on the programming while I wait for larger motors and other parts to arrive.

Step 1: Problem and Parts

Often in the theatre, we have the need to lift or move small loads in various hard to reach places. This is a test for a wireless remote winch.

The video gives an overview of the variable speed, manually controlled test rig. You can see the transmitter Arduino hooked up to a 10k variable potentiometer and NRF24L01, and the receiving Arduino which is hooked up to the servo.

Parts needed:

(2) Arduino Uno boards

(2) NRF24L01 transceivers

(2) NRF24LO1 backpacks

(1) 10k Ohm variable resistor

(1) LED

(1) push button

(1) 220 Ohm resistor

(1) 2k resistor

(1) continuous rotation servo

(1) 5 volt power supply

(1) Breadboard

Various wires

Step 2: Construction- Cue Version

The first version is a cue button style. Pressing a button will activate the winch, raising the load at a preprogrammed speed and duration.

The button causes the transmitter to send a message. When the receiving arduino registers that it has gotten a message, it activates the winch cue, then turns off the indicator light and the servo when it completes.

This setup has some limitations, as you can see from the video, getting consistent travel of the winch is difficult, as there is no position feedback.

The code for the receiver and transmitter is identical, and is posted below.

The include commands aren't formatting properly, so don't forget to add <> around them.

<p>#include SPI.h<spi.h><br></spi.h></p><p>#include RH_NRF24.h<rh_nrf24.h>
#include ServoTimer2.h<servotimer2.h>
// Singleton instance of the radio driver
RH_NRF24 nrf24;</servotimer2.h></rh_nrf24.h></p><p>#define servoPin 6  //define the pins for the servos</p><p>ServoTimer2 servoRoll;</p><p>int redLed = 4;  //on receiver, confirmation of reception
int button = 5;  //on transmitter, makes it chooch
int nochooch = 1500;  //servo does not move when fed 1500
int chooch = 0;  //0 is max in one direction, 3000 is max in other.
//speed only seems to decrease in 1200-1500 range, and 1500-1800 range</p><p>void setup() 
{
  servoRoll.attach(servoPin);  //attach a pin
  
  Serial.begin(9600);
  
  pinMode(redLed, OUTPUT);
  pinMode(button, INPUT);
  while (!Serial) 
    ; // wait for serial port to connect. Needed for Leonardo only
  if (!nrf24.init())
    Serial.println("init failed");
  // Defaults after init are 2.402 GHz (channel 2), 2Mbps, 0dBm
  if (!nrf24.setChannel(68))  //set channel for tranceiver here
    Serial.println("setChannel failed");
  if (!nrf24.setRF(RH_NRF24::DataRate2Mbps, RH_NRF24::TransmitPower0dBm))
    Serial.println("setRF failed");    
}</p><p>void loop()
{
  
  if (digitalRead(button) == HIGH) {
    //button is pressed, message should be sent,   </p><p>   // Send a message
    uint8_t data[] = "Aloha";
    nrf24.send(data, sizeof(data));
    nrf24.waitPacketSent();
 //   Serial.println( "sent!" );  //for debug
    
  } 
  else {
    // Wait for a message
    uint8_t buf[RH_NRF24_MAX_MESSAGE_LEN];
    uint8_t len = sizeof(buf);
    while (nrf24.waitAvailableTimeout(100) && nrf24.recv(buf, &len))
    //don't use timeouttime above for delay-  it will delay seeking for
    //button push as well
    {   
        //something was received, turn the right LED on
        digitalWrite(redLed, HIGH); 
        servoRoll.write(chooch);  //speed and direction of winch
        delay(5000);     //run winch for 5 seconds
    }      
    digitalWrite(redLed, LOW);  
    servoRoll.write(nochooch); //1500 is integer for stop
    delay(10); //slight pause in program, helpful for smooth
  }
}</p>

Step 3: Step 3: Variable Speed Version

The variable speed version is constructed similarly. The key difference is that it is constantly transmitting a variable for the speed and direction of the the servo. This allows for live adjustment and control of the winch using the potentiometer attached to the transmitter. The code here takes the analog Read value from the potentiometer, scales it to fit in the range of the servo, and then transmits it. The receiver takes the speed and applies it to the servo. Control is surprisingly precise with this setup. I'm using a different library for the RF24L01 which worked more reliably for me.

The code for the transmitter is below:

<p>/* Transmitter Code<br>*  Code to read  a pot position and transmit it with a RF24L01+ to a receiver 
*  Credit to Mark Hughes for sharing his remote control project that this is
*   derived from.
*/</p><p>#include <spi.h>
#include <rf24.h></rf24.h></spi.h></p><p>// Radio Configuration</p><p>RF24 radio(9,10);
byte addresses[][6] = {"1Node","2Node"};
bool radioNumber=1;
bool role = 1;  //Control transmit 1/receive 0</p><p>// Decide where you are going to plug the joystick into the circuit board.</p><p>int UpDown_Pin = 0;        // Plug 10k ohm variable resistor into Analog pin 0</p><p>// Create variables to read joystick values</p><p>float UpDown_Input ;       // Variable to store data for Fore/Aft input from joystick</p><p>// Create variables to transmit servo value</p><p>int UpDown_Output;       // Expected range 0 - 190, 95 is no chooch</p><p>void setup() {
    Serial.begin(9600);                   // Get ready to send data back for debugging purposes
    radio.begin();                        // Get the transmitter ready
    radio.setPALevel(RF24_PA_LOW);        // Set the power to low
    radio.openWritingPipe(addresses[1]);  // Where we send data out
    radio.openReadingPipe(1,addresses[0]);// Where we receive data back
}
void loop() {
    UpDown_Input = analogRead(UpDown_Pin) ;             // Read the Fore/Aft joystick value
    
    UpDown_Output = map(UpDown_Input, 0, 1024, 0, 190);        // Convert the Fore/Aft joystick value to a Servo value (0-190)
     
    </p><p>    //  Serial.print(ForeAft_Output);
    radio.stopListening();                                 // Stop listening and begin transmitting
    delay(50);                                            // make delay longer for debugging
    if(radio.write(&UpDown_Output, sizeof(UpDown_Output)),Serial.println("sent UpDown"));              //Send UpDown data
    
    radio.startListening();                                // Get ready to receive confirmation from receiver
}</p><p>//// Function to convert and scale the Fore/Aft data  NOT NEEDED YET
//
//float convertForeAftToServo(float y) {
//    int result;
//    result = ((y - Aft_Limit) / (Fore_Limit - Aft_Limit) * 180);
//    return result;
//}
//
//// Function to convert and scale the Left / Right data  NOT NEEDED YET
//// Can be replaced with Map function
//float convertLeftRightToServo(float x) {
//    int result;
//    result = ((x - Left_Limit) / (Right_Limit - Left_Limit) * 180);
//    return result;
//}</p>

The code for the receiver is below:

<p>/*  Receiver Code <br>*   Code to receive data from RF24L01+ and use it to control a continuous servo
*   Credit to Mark Hughes for sharing his remote control project that this is
*   derived from.
*   */</p><p>#include Servo.h<servo.h>
#include SPI.h<spi.h>
#include RF24.h<rf24.h></rf24.h></spi.h></servo.h></p><p>//Radio Configuration</p><p>bool radioNumber=0;
RF24 radio(9,10);
byte addresses[][6] = {"1Node","2Node"};
bool role = 0;  //Control transmit/receive</p><p>// Create variables to control servo value</p><p>Servo UpDown;</p><p>unsigned int UpDown_Output;       // Expected range 0 - 190, 95 is no chooch</p><p>void setup() { 
    Serial.begin(9600);        // Get ready to send data back for debugging purposes
    UpDown.attach(6);         // Plug a servo signal line into digital output pin 6
    
    radio.begin();             // Initialize radio
    radio.setPALevel(RF24_PA_LOW);    // Set the power output to low
    radio.openWritingPipe(addresses[0]);
    radio.openReadingPipe(1,addresses[1]);
    radio.startListening();
}
void loop() {
    delay(50);               //increase for debuggy, decrease to decrease jitter
    if(radio.available()){
        radio.read(&UpDown_Output,sizeof(UpDown_Output));
        } else {Serial.print("No radio");
    }
    Serial.print(UpDown_Output);
    Serial.print("\t");
    
    UpDown.write(UpDown_Output);   // Command the UpDown servo to a position, or, where the magic happens
    
    }</p>

Step 4: Destructive Testing

Limitations-

It's a spool of thread attached to a servo- it certainly cannot lift a kitty, but it makes a great toy for them.

As is, this might be able to pull a mouse across the stage, but is not able to handle much more than that. I plan to take the lessons that I learned from this project and apply them to a full scale winch.

The Arduino has difficulty handling more than one thing at a time. A quadrature encoder hooked directly into the Arduino taxes the processor, and it can't listen for radio commands and count the encoder at the same time. Best practice would be to offload that work onto a different processor, like a Kangaroo and SyRen setup.