geezacoleman / OpenWeedLocator

An open-source, low-cost, image-based weed detection device for in-crop and fallow scenarios.
MIT License
342 stars 61 forks source link

moving to 50 cm nozzle. #68

Closed manninb closed 1 year ago

manninb commented 1 year ago

What would be needed to operate the systems for a 50cm nozzle spacing? Does anybody have the capacity to do the coding if required. Most commercial spraying works on 50 cm spacing.

geezacoleman commented 1 year ago

There are a couple of ways to change this:

  1. You could raise the height of the camera to 2m so that four lanes cover 50cm each, but I don't think the resolution will be high enough for good performance on small weeds.
  2. Best option is to change nozzleNum=4 to nozzleNum=2 and leave the OWL at 1m height. The OWL will only use the first two values in the dictionary that maps the nozzle to the pin on the Raspberry Pi that turns it on. So just make sure you connect the two solenoids to those pins.
      # nozzleDict maps the reference nozzle number to a boardpin on the embedded device
        self.nozzleDict = {
            0: 13,         <- it will only use these first two pins
            1: 15,         <- and this one
            2: 16,
            3: 18
        }

The nozzleNum value is found in greenonbrown.py Line 605:

    owl = Owl(videoFile=args.video_file,
              show_display=args.show_display,
              recording=args.recording,
              exgMin=25,
              exgMax=200,
              hueMin=39,
              hueMax=83,
              saturationMin=50,
              saturationMax=220,
              brightnessMin=60,
              brightnessMax=190,
              resolution=(416, 320),
              nozzleNum=2,                                   <-- this is what you want to change from 4 to 2 (or however many you like)
              framerate=args.framerate,
              exp_mode=args.exp_mode,
              exp_compensation=args.exp_compensation,
              awb_mode=args.awb_mode,
              sensor_mode=args.sensor_mode,
              parameters_json=None
              )
geezacoleman commented 1 year ago

Keep me posted about how this goes @manninb! Would be great to get some videos/photos of the 50cm nozzle setup. I'll close it for now, but feel free to reopen/add more comments if needed.

Kmrfarmsinc commented 10 months ago

So I was trying to shut off nozzles as well but I'm getting confused on the directions above. I understand what I need to do but I'm not sure what specific commands I need to make it work. I tried to use the information above in your first reply but I didn't have any luck.

I have a blueberry orchard and I would be spraying one side of the row at a time so I would only need 1 nozzle. Eventually I want to make another setup with OWL for the opposite side of the row, so i can spray the entire row in one pass.

Could you go over again how to take out nozzles?

geezacoleman commented 10 months ago

That sounds like an interesting use case, would be great if you can share some photos of the completed setup over in the community builds page once you're done!

What specific issues were you having with changing nozzle number?

If it's just one nozzle, change the nozzleNum=4 parameter on Line 528 in owl.py to 1. That way the image will be divided into a single zone and only activate one nozzle.

The nozzleDict I talk about above just maps each zone within the image, to a GPIO pin on the Pi. These pins are connected to the relay control board. So if the wrong GPIO number is used because the mapping is incorrect, then the wrong pin is activated and the relay control board probably won't activate, or perhaps the wrong section is activated. As mentioned above the system will only use the first nozzle in the dictionary, but to be certain, you can delete the other parts of the dictionary so it will be

self.nozzleDict = {
            0: 13        # it will only use this pin
        }

Just make sure the wire from GPIO 13 is connected. You can copy this code in exactly as it is here to replace the dictionary starting Line 114 in owl.py if that helps.

I've tested this on my own laptop (not OWL device though) and it seems to work, but let me know how you go and if you have any more questions.

Kmrfarmsinc commented 10 months ago

So, I was able to find the owl.py doc to change the number of nozzles to 1 and the self NozzleDict to only read 0: 13, but when I try and run it the program says 0 nozzles when starting up through the terminal. Also, I had the camera working but it randomly shut off after about 20 seconds from running the program. Don’t know if I deleted more than I should or what but these are the pictures of the terminal and the owl.py changes. IMG_3475 IMG_3474 IMG_3473

geezacoleman commented 10 months ago

In Python things are generally 0 indexed, so they start counting from 0 not 1. I carried this over into the nozzle numbering on the display (hence Nozzle 0) appears, but that just means the first nozzle, not that there are zero nozzles operating. I think I'll update that for the label above each nozzle, because it isn't entirely clear. This means it is working correctly.

I would recommend running ./owl.py --show-display --exp-mode 'auto' and see if it closes after 20s or not. I think in the focusing mode it may be running into issues with the almost entirely dark image and the division by 0. In your dictionary you do have an unnecessary comma after 13. So I would delete that too and try again.

There is potentially an unseen bug there somewhere too, but hard to say what just yet! I would also recommend running the bash update_owl.py as well if you haven't already.

Kmrfarmsinc commented 10 months ago

Alright, thanks for the clarification on the nozzles. I took out that extra comma next to the 13 in Line 116.

I had a CAMERA ERROR the first time I tried it but it said the run the next step which was the Latency Focusing step. I got the PID number this time so I ran the command of sudo kill enter_your_PID_number_here. When I ran this nothing happened so I assumed it worked.

Next I tried ~/owl/./owl.py --show-display and that didnt work with pulling up the camera feed but ./owl.py --show-display --exp-mode 'auto' got the camera to pop up and now it says the correct Nozzle 0 which is one nozzle working

I don't know if the program is going to need more tuning but it seems to be working as of now. As of now, I only have one more question and that is, if you run the owl program and the camera feed pops up, can you not do anything else to the program like tweaks? And how you do you turn the camera feed off without exiting the terminal?

geezacoleman commented 10 months ago

Ok great, that all sounds promising!

Everytime you reboot the OWL it will start running in the background, so if you want to run it from the terminal again for tuning/testing purposes, you'll need to do the ps -C owl.py and then sudo kill pid_number (just make sure to replace pid_number with the program number that appears).

How do you mean tweaks to the program? You can change the threshold values on the sliders pane which will change detection performance/sensitivity. But changes to camera settings require you to stop and restart it. That just requires you to press Escape when you have the video feed highlighted and then running ./owl.py again.

If you want to permanently change exposure mode, exp compensation (for example if the image is too dark outside) that requires changing the defaults between Lines 486-513. This way when you disconnect the screens and just want it to run on your system, it will run automatically to what you set previously.

I know this is a bit clunky and it will be improved in later iterations.

These are the lines you'll need to change - just wherever it says default. E.g. change default=-4 for exp-compensation to default=0 if you want a brighter image.

    ap = argparse.ArgumentParser()
    ap.add_argument('--input', type=str, default=None, help='path to image directory, single image or video file')
    ap.add_argument('--show-display', action='store_true', default=False, help='show display windows')
    ap.add_argument('--focus', action='store_true', default=False, help='add FFT blur to output frame')
    ap.add_argument('--recording', action='store_true', default=False, help='record video')
    ap.add_argument('--algorithm', type=str, default='exhsv', choices=['exg', 'nexg', 'exgr', 'maxg', 'exhsv', 'hsv', 'gog'])
    ap.add_argument('--conf', type=float, default=0.5, choices=np.arange(0.01, 0.99, 0.01), metavar="2 s.f. Float between 0.01 and 1.00",
                    help='set the confidence value for a "green-on-green" algorithm between 0.01 and 1.00. Must be a two-digit float.')
    ap.add_argument('--framerate', type=int, default=40, choices=range(10, 121), metavar="[10-120]",
                    help='set camera framerate between 10 and 120 FPS. Framerate will depend on sensor mode, though'
                         ' setting framerate takes precedence over sensor_mode, For example sensor_mode=0 and framerate=120'
                         ' will reset the sensor_mode to 3.')
    ap.add_argument('--exp-mode', type=str, default='beach', choices=['off', 'auto', 'nightpreview', 'backlight',
                                                                      'spotlight', 'sports', 'snow', 'beach',
                                                                      'verylong', 'fixedfps', 'antishake',
                                                                      'fireworks'],
                    help='set exposure mode of camera')
    ap.add_argument('--awb-mode', type=str, default='auto', choices=['off', 'auto', 'sunlight', 'cloudy', 'shade',
                                                                     'tungsten', 'fluorescent', 'incandescent',
                                                                     'flash', 'horizon'],
                    help='set the auto white balance mode of the camera')
    ap.add_argument('--sensor-mode', type=int, default=0, choices=[0, 1, 2, 3], metavar="[0 to 3]",
                    help='set the sensor mode for the camera between 0 and 3. '
                         'Check Raspberry Pi camera documentation for specifics of each mode')
    ap.add_argument('--exp-compensation', type=int, default=-4, choices=range(-24, 24), metavar="[-24 to 24]",
                    help='set the exposure compensation (EV) for the camera between -24 and 24. '
                         'Raspberry Pi cameras seem to overexpose images preferentially.')
    args = ap.parse_args()
geezacoleman commented 10 months ago

Improvements to some of these issues have been made in #103.

Kmrfarmsinc commented 9 months ago

Having a problem again with the camera feed cutting out. I was able to get the PID, kill that program, get the camera to pop up but it will turn off after 10-20 seconds. Any solution?

geezacoleman commented 9 months ago

A few questions, which should hopefully narrow it down:

Kmrfarmsinc commented 9 months ago

Yes I am using the default green-on-brown detection mode.

The power cord are all good, tested those myself.

I see the GPIO pins but I have the expansion board that goes in those pins. I am going to include the pictures of the hardware.

The camera will turn on and remain on. The problem I found is that I turned my phone camera on and was moving it closer and further away to try and get a detection. I got the camera to pick it up but when i get about 20 cm away from the lens, its shut down. It makes me think it is a sensitivity issue but im not sure.

Im using a HD Raspberry Pi with the ribbon cable. image1 image0

geezacoleman commented 9 months ago

Ok thanks for sharing the hardware setup - as you say, power looks a lot more robust than the USB-C adapter, so I don't think that should be an issue. When you say you move the phone camera closer/further away, is that like a green object or similar to test it? If you're moving the Pi HD camera and it cuts out, I'm guess that might be a cable issue then. In either case, I'd double check the camera ribbon connection. I have had similar issues previously with old cables that have been bent too much.

For the software, do you have the latest version of the OWL software? I ask because we had this issue from some buggy code a while back but have since fixed it. To diagnose the software - can you leave it running with no detections being made? There might be an issue running only one detection zone and detections falling outside that.

There shouldn't be an issue getting too close to the camera - I've done that plenty of times, it will just get a bit blurry but won't cause the camera to cut out. I would advise against running focus_owl.sh too long though - there could be issues there with too much blur.

To summarise:

  1. check ribbon cable
  2. leave software running with/without green detections and make sure it is updated using update_owl.sh. 2a. try running it with the default four lanes and see if it works. If it does but fails with 1 lane/detection zone then you'll know it's that.
  3. Make sure it isn't running the focusing script.
  4. are you using the original owl image downloaded form github or the latest Raspbian OS from Raspberry Pi? The latter will cause issues because it will want to run libcamera not picamera.
Kmrfarmsinc commented 9 months ago

The ribbon for the camera was a little loose but it still happened after I fixed the ribbon.

I am going to give a picture below and I’m wondering if this could be the problem. IMG_3500

geezacoleman commented 9 months ago

In that screenshot, you're working in the global environment for the OWL - we run the OWL software in a virtual environment, which is a way of keeping all the various other packages together. Helps with version control and managing conflicts. The issue is that anything outside the virtual environment owl is inaccessible to the owl software.

If you pip install things. always pip install them into the virtual environment owl, otherwise you'll run into issues.

To install into the virtual environment, you first need to activate it and then run the pip install commands.

workon owl
pip install --upgrade pip
pip install blessed

(edit) Looking at your image more carefully I realised you must have already run pip install -r requirements.txt. Was this into the owl environment?

I would just recommend running:

workon owl
bash update_owl.sh

This will download the latest OWL software, and install all the right dependencies into the right virtual environment too.

Just make sure you're using the OWL image downloaded from this repository. If you use one of the latest Raspbian versions the software definitely won't work. It's something we're working on, but won't be done for a couple of months still.