Help us with this cable winch counter!

Hi guys!

Sorry for my English.

Hope you can help me out a bit. I took over this project from a former employee and sadly my projects including an Arduino are far between – so my programming skills are pretty rusty.

In the code below I’ve tried to write some code for the project, which should do the following:

Imagine you’re on a ship and your task is to control a winch, which has a lot of cable on it and you need to lower an instrument into the ocean. But as a winch controller you must also make sure you know how much cable you’ve rolled into the ocean so the instruments don’t hit the bottom, and at which speed you roll out the cable. When rolling the cable backwards onto the winch, the speed must also be known and it’s also nice to know how much cable is left.

Now – we got the hardware for this and it’s all setup and working. It consists of two Hall Effect Sensors, which sends a “LOW” when it senses a piece of magnetic material passing by. The Arduino reads this value and sends text to a 4x20 Blue LCD Display.

What we need your help with is this:
Since the Hall Effect sensors are mounted on the winch with a few centimeters between, they both go “LOW” with a small delay between them, no matter if the winch is rolling forward or backwards, which is logical to understand, they’re not doing anything wrong.

But – I can’t get the code right to figure out HOW the Arduino should know and tell the display if the winch is rolling forwards or backward (Cable in or out). I think it should be possible somehow, but it’s pretty difficult to differentiate the signals, since those two sensors acts in the same way and both activates with a small delay, no matter what direction the winch is rolling.

So what do you think could be done? Hope the code below is somewhat understandable.

What really happens with the current code below, is that the counter first counts up, shortly after it counts down, then up, then down… so the counting isn’t really going anywhere.
The speed at which you run the winch is working fine, it don’t care if the cable is being run in or out.

P.S - Sorry for all the O’s - just like them for separation :smiley:



//OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO
#include <Wire.h>  // Comes with Arduino IDE
#include <LiquidCrystal_I2C.h> 
//OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO

int sensor1 = 2;  // Magnetsensor 1 input from Hall-Effect Sensor 1.
int sensor2 = 3;  // Magnetsensor 2 input from Hall-Effect Sensor 2.

int winch_switch = 7;  // Switch to choose between CTD or WP2 winch.
int sensor_count = 0;  //Set the sensor count to zero.
int sensor_last_value = LOW;
 
volatile float counting_range; // Defines how much the counter should count up or down when the Magnetsensor is activated.
volatile float Total_cable;  // Defines in total how much the cable has been rolled in or out.


unsigned long  Start_timer; //starts the timer when a Magnetsensor is activated.
unsigned long  Saved_timer; //Saves how far the timer counted.
volatile float Timedifference; //Timedifference in milliseconds.
volatile float Timer_MPM;  // Timer for meters per minute.
volatile float Timer_seconds;  //Timer time in seconds.
volatile float Timer_minutes; //Timer time in minutes.
volatile int   Cable_MPM; //Saves the cable length rolled in or out in meters per minute.


//OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO
//Setup blue LCD Display.

// set the LCD address to 0x3F for a 20 chars 4 line display
// some displays may respond on 0x27 instead!
// Set the pins on the I2C chip used for LCD connections: addr, en,rw,rs,d4,d5,d6,d7,bl,blpol

LiquidCrystal_I2C lcd(0x3F, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);  // Set the LCD I2C address

//OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO

void setup() 
  { 
    
   lcd.begin(20,4);         // initialize the lcd for 20 chars 4 lines, turn on backlight

  // ------- Quick 2 blinks of backlight  -------------
  for(int i = 0; i< 3; i++)
  {
    delay(250);
    lcd.noBacklight();
    delay(250);
  }
  
  lcd.backlight(); // finish with backlight on 
    
    pinMode(2, INPUT_PULLUP); // Enable internal pull-up resistor on pin 2
    pinMode(3, INPUT_PULLUP); // Enable internal pull-up resistor on pin 3

    pinMode(winch_switch, INPUT);          
    digitalWrite(winch_switch, HIGH);     
        
    attachInterrupt(0, sensor_counter, CHANGE); 
    attachInterrupt(1, sensor_counter, CHANGE); 

    lcd.setCursor(0,0); 
    lcd.print("NULSTIL I OVERFLADEN"); // Means "reset at the surface"
    
    lcd.setCursor(0,1);
    lcd.print("--------------------");
    
    lcd.setCursor(0,2);
    lcd.print("SPEED ");
    lcd.write(0x7E);    
    
    lcd.setCursor(0,3);
    lcd.print("METER ");
    lcd.write(0x7E);    
}

//OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO

void sensor_counter () 
{
  
  if ((sensor_last_value == HIGH) && (digitalRead(sensor1) == LOW && (digitalRead(winch_switch) == LOW))) // In this mode Winch_switch is chosen for CTD winch.
  {
   
      Start_timer = millis();
      Timedifference = Start_timer-Saved_timer; 
      Timer_seconds = Timedifference/1000;          //Some time converting from mS to seconds.        
      Timer_minutes = Timer_seconds/60;             //Some time converting from seconds to minutes.              
      Cable_MPM = 0.10/Timer_minutes;               //Used for calculating the speed of rolling cable out (meters per minute).                    
      Saved_timer = Start_timer;                             
    
                                                                         
    if (digitalRead(sensor2) == LOW)           
      {
      sensor_count = sensor_count + 1; // Count up if sensor2 goes low first.                           
      }   

       else
       {
        sensor_count = sensor_count - 1; // Count down if sensor1 goes low first. 
       }
      
      counting_range = sensor_count * 0.10; //Count up 10 centimeters every time the magnetic sensor is activated.
      Total_cable = counting_range;
      
    }


  
    if ((sensor_last_value == HIGH) && (digitalRead(sensor1) == LOW && (digitalRead(winch_switch) == HIGH))) // In this mode Winch_switch is chosen for WP2 winch.
  {
    
      Start_timer = millis();
      Timedifference = Start_timer - Saved_timer; 
      Timer_seconds = Timedifference/1000;    //Some time converting from mS to seconds.             
      Timer_minutes = Timer_seconds/60;       //Some time converting from seconds to minutes.                    
      Cable_MPM = 0.10/Timer_minutes;         //Used for calculating the speed of rolling cable out (meters per minute).               
      Saved_timer = Start_timer;                            
         
                                                                         
    if (digitalRead(sensor2) == LOW)           
      {
      sensor_count = sensor_count - 1; // Count up if sensor2 goes low first.                           
      }   

       else
       {
        sensor_count = sensor_count + 1; // Count down if sensor1 goes low first. 
       }
      
      counting_range = sensor_count * 0.10; //Count up 10 centimeters every time the magnetic sensor is activated.
      Total_cable = counting_range;
      
    }

   sensor_last_value = digitalRead(sensor1);
}
//OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO


void loop() 

{ 
       
    if(millis() - Start_timer > 4000)    
    {
        //delay(500);
        Cable_MPM = 0;
        lcd.setCursor(11,2);
        lcd.print("         "); //Inserting some blank space for this type of display.
    }
    
      
    if (digitalRead(winch_switch) == HIGH)
    {
        lcd.setCursor(10,2);
        lcd.print(Cable_MPM,1); //Write the rotation speed on display when winch_switch is HIGH.
    }
    
    if (digitalRead(winch_switch) == LOW)
    {
        lcd.setCursor(10,2);
        lcd.print(Cable_MPM,1); //Write the rotation speed on display when winch_switch is LOW.
    }
    
    if(digitalRead(winch_switch) == HIGH)
    {
        lcd.setCursor(10,3);
        lcd.print(Total_cable,2); //Write the total cable length rolled out, on display, when winch_switch is HIGH.
        lcd.print(" ");
    }
    
    if(digitalRead(winch_switch) == LOW)
    {
        lcd.setCursor(10,3);
        lcd.print(Total_cable,2); //Write the total cable length rolled out, on display, when winch_switch is LOW.
        lcd.print(" ");
    }
}
  
//OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO

Hi, you don't need to use interrupts for this project. They just make the code more complex, and don't give any advantage.

What speed does the winch turn, approximately?

How far apart are the two sensors? Do the LOW signals from the two sensors overlap at some angles?

Hi Paul.

Thanks for your reply.

What do you suggest could (code-wise) be used otherwise instead of interrupts?

The winch can go really fast, and really slow. The speed depends on the depth of the ocean, so if we need
to lower to 1000 meters, we set the speed faster to save some time.

But to give you an idea about a typical speed, then that would be 15 and 30 meters per minute, the cable needs to be run in or out with.

The space between sensors (centre to centre) is about 5 centimeters. The angles are the same for when a sensor goes LOW, they cannot go LOW at the same time the way it's constructed.

Rotation of the winch will not give length of cable as it will vary as the diameter increases/ decreases. 2 hall effect set up as a quadrature signal will give you direction though.

marengsen:
The winch can go really fast, and really slow.

You need to give us numbers for what you mean by fast or slow. How many pulses per second from the sensor.

If the pulses are slow by Arduino standards you can just use digitalRead() to test for them. However I think I would use interrupts but my ISR code would be very short compared to yours. Something like this
EDIT to add that I am assuming these are RISING or FALLING interrupts (which ever is the front edge of the pulse) rather than CHANGE interrupts.

void (sensorAdetect) {
   sensorAmicros = micros();
   sensorDetect ++;
}

void (sensorBdetect) {
   sensorBmicros = micros();
   sensorDetect ++;
}

Then your code in loop() to read the data would be something like

void loop() {
  if (sensorDetect >= 2) {
    noInterrupts()
      copySensorAmicros = sensorAmicros;
      copySensorAmicros = sensorAmicros;
     sensorDetect = 0;
    interrupts();
    speed = copySensorBmicros - copySensorAmicros;
    if (speed < 0) {
      // one direction
    }
    else {
      // other direction
    }
    speed = abs(speed);
  }
}

…R

PS. after reading Reply #63 I had been assuming the magnets triggering the sensors are embedded in the cable. if they are on the winch drum then what @bluejets says is correct.

Hi again both.

Good replies. But yes, the sensors are not mounted on the winch directly, but on a sort of cable block, which is just a wheel that helps bend the cable from the drum and feed it outwards, but also makes sure the cable is being put as a nice layer on the drum when going backwards (if that makes a bit of sense).. bit hard to explain. But anyway the sensors are not dependant on the cables thickness or layers.

Could you try to explain what you mean with a quadrature setup and how this should be done in practice?

/Cheers!

Hi,
The two Hall-Effect signals, when they drop to gnd, do the pulses overlap or are they separated?

Tom... :slight_smile:

marengsen:
But yes, the sensors are not mounted on the winch directly, but on a sort of cable block, which is just a wheel that helps bend the cable from the drum and feed it outwards,

That should measure the distance and speed properly. In the code I suggested in Reply #4 I was assuming the two sensors are triggered separately without any overlap.

...R

@TomGeorge.

The two sensors are setup with no overlap, as in top of the drawing you posted.

@Robin2 - Thanks mate, ill try to figure out what your code means and if it could be implemented somehow in my own. As I said, I'm quite rusty in programming :slight_smile:

-But do you think your code could fix my problem with counting forward and backwards with just the two sensors?

The code in #4 looks very sensible to me, and would allow you to know which direction you're rolling in and how many rotations worth of rope you have winched.

The only problem you may run into is if you roller happens to be in between the two sensors the moment you start it up. Then the second sensor is seen first, and the speed is very slow and counted backwards. You could add code where the previous A and B times are stored as well, to make sure which one is the shorter, as extra precaution.

The time in micros should be long enough to get a pretty accurate speed. If that's not accurate enough, you could instead time how long it takes between two pulses from sensor A, which would be a complete rotation.

Notwithstanding the dirt and other obstructions, you may be better served by painting half the roller white, and the other black. (or using radial stripes)
That will give you longer intervals to measure the rotation speed, and the reflective sensors can be placed with 'less tolerance' to provide direction and speed. Using IR illumination will help see through dirt and incidental daylight... this all needs some testing in-situ.

Detect only the leading edges, in case the paint edge is obstructed or contaminated.

Remember the sensor can be located anywhere else on the pulley shaft as long as it is mechanically synchronous to the pulley - allowing for slippage of the cable in any case!

wvmarle:
The only problem you may run into is if you roller happens to be in between the two sensors the moment you start it up. Then the second sensor is seen first, and the speed is very slow and counted backwards. You could add code where the previous A and B times are stored as well, to make sure which one is the shorter, as extra precaution.

The OP could probably deal with that by distinguishing between the short time between the two triggers when the magnet passes the pair of sensors and the much longer time until the next revolution. I am assuming the two sensors are closer together than half the circumference of the wheel.

It would be a huge help if the OP would provide some numbers and a drawing or diagram of the sensor arrangement.

...R

^^^^ This where higher resolution (more magnets or stripes) can help.
The distance travelled to the first edge at startup will be shorter.

BTW, a single track of magnets (on a steel pulley?) around the perimeter, with two hall sensors immediately adjacent to each other would also work to collect the quadrature pulses.
(This makes me think a toothed ring on the pulley, that 'shorts' the magnetic field' will work better... you can get hall sensors that work that way.)

Agree with R2 - more mechanical detail will help, and this is definitely a hostile environment for the mechanicals and wiring...!

You still have to deal with slippage of the cable against the rollers, and stretch as the cable length/weight increases!

EDITED for added detail

lastchancename:
this is definitely a hostile environment for the mechanicals and wiring...!

From the OP I understand that the two sensors are close together, so maybe a few percent of the total rotation apart.

They describe a magnet on the roller, and two hall effect sensors - this should be a pretty solid installation, and rather impervious to dirt. No moving parts that can get stuck due to the dirt. Magnetic fields go right through it (of course I assume strong magnets so the sensors are getting a strong signal when it's clean).

Optical solutions as suggested above will be affected by dirt, to a much greater extent. I don't see that working.

You still have to deal with slippage of the cable against the rollers.

If the roller that is being tested is freely rolling this should be no problem.

This might be a silly question, but why can't you use your on-board sonar to track the depth of your instrument? You're on a vessel which is big enough to carry a winch with a kilometre of cable on it, so I'm assuming it will also be big enough to need fairly accurate sonar.

Hi guys!

Thank you all very much for your help, really appreciate it and very kind of you.

You’re all correct, a picture would be nice to have, so I have some very fresh ones for you.

Hope they get attached from our overpowered 0.4 Megabit Satellite connection :smiley:

Hi,
Are you sure the pulses don't overlap, that looks like its setup for just that purpose so you can easily detect direction of rotation.
If anything, the sensors need to be closer together.

Tom... :slight_smile:
Just an observation.

Is every single one of those screwed-on metal bits a magnet? I assume the two cylinders are the hall sensors, correct?

@TomGeorge Care to explain what you mean with being closer and how that could easily detect direction? :slight_smile:

@wvmarle - Correct, those metal pieces eminates the magnetic field which are sensed by the two sensors in the box as each piece passes by.

Images from Reply #15 so we don’t have to download them. See this Image Guide

a842a4e3b96baf18733d5996f237911e4f624070.jpg

57279a129d227ac6412e516db73d7a44905c71ba.jpg

3bcb92e633392511e2c43faaeb443a61ffae4234.jpg

…R