Hi all,

I have a robot which detects an object using hsl filtering and a blob counter to draw a rectangle around the object. What I am trying to do is get the robot to move to its right if the object is on the right side, else it moves to the left. Essentially I want it to work as a goalkeeper, so as the object comes towards it, it moves into the objects path.

I am far from a C# expert and have tried various ways to get it to function properly, to no avail. When the program runs the robot seems to randomly move left and right as it pleases, quite often doing so until it loses sight of the object, in which case it just carries on going.

Below is my controller method, any chance somebody could help me fix this so it runs as intended? If required I can include my DetectObject method or the form used to call the controller method, as I am not sure where the problem lies.

        public void Bangbang()
        {
            int speed = 5;

            while (true)
            {
                Bitmap image = API.Camera.GetImage();
                Rectangle rects = DetectObject(image);

                //RecImage(image);

                double error = (rects.X + rects.Width / 2) - (image.Width / 2);
                if (error > 0)
                    //API.Movement.ManualDrive.RotateRight(speed);
                      API.Movement.ManualDrive.StraightRight(speed);
                else //if (error < 0)
                    //API.Movement.ManualDrive.RotateLeft(speed);
                      API.Movement.ManualDrive.StraightLeft(speed);


                //else
                  //  API.Movement.ManualDrive.Stop();
            }
        }

I had a slightly different piece of code recommended to me in which if (error > 0) was replaced with if (error), however this produces an error about converting double to bool. I also tried Convert.ToBoolean but this didn't seem to do anything.

I've been stuck on this program for days and could really use a hand! Thank you :)

Dani AI

Generated

Three quick causes explain the behaviour you’re seeing: the control loop is running without guards, there’s no “no-object” check so the robot keeps acting on an empty rectangle, and the loop oscillates because tiny detection noise flips the left/right decision repeatedly. , your DetectObject returns an empty rectangle when nothing is found, and Bangbang needs to treat that as “no sight” and stop moving immediately.

Fix checklist (apply in this order)

  • Run the controller off the UI thread (don’t call Bangbang directly from MainForm_Load). Start it in a background Thread/Task so the UI and image pipeline keep working.
  • Treat a zero-sized rectangle as “no detection” and call Stop() there.
  • Add a dead zone/hysteresis around the image center (ignore small errors) to prevent toggle noise.
  • Smooth the measured center (simple moving average of last N centers) or use a small low-pass filter to avoid reacting to single-frame jitter.
  • Limit loop rate (Thread.Sleep(30–100 ms) or a timer) and dispose images (using / Dispose) to avoid resource pressure.

Minimal example (concept only — not a drop-in for your posted code)

// keepRunning controlled elsewhere
while (keepRunning)
{
    using (Bitmap img = API.Camera.GetImage())
    {
        var rect = DetectObject(img);
        if (rect.Width == 0 || rect.Height == 0) { API.Movement.ManualDrive.Stop(); }
        else
        {
            // moving average + dead zone
            int center = rect.X + rect.Width/2;
            // enqueue/avg omitted for brevity
            int error = avgCenter - img.Width/2;
            if (Math.Abs(error) <= deadZone) API.Movement.ManualDrive.Stop();
            else if (error > 0) API.Movement.ManualDrive.StraightRight(speed);
            else API.Movement.ManualDrive.StraightLeft(speed);
        }
    }
    Thread.Sleep(50);
}

Extra tips: log centerX over time to pick a sensible deadZone and smoothing window; ignore very small blobs by checking area before accepting a rectangle; if the robot supports variable rotation speed, map error magnitude to speed (proportional control) instead of pure bang-bang. Finally, ensure any RecImage UI updates are marshalled (BeginInvoke) when raised from the background thread.

Should it help, below is my DetectObject method:

            public Rectangle DetectObject(Bitmap image)
            {
                //New HSL filter 
                AForge.Imaging.Filters.HSLFiltering hslFilter = new AForge.Imaging.Filters.HSLFiltering();

                //HSL colour range (set to orange)
                hslFilter.Hue = new AForge.IntRange(0, 50);
                hslFilter.Saturation = new AForge.Range(0.7f, 1);
                hslFilter.Luminance = new AForge.Range(0.2f, 0.7f);

                //Apply filter to image
                hslFilter.ApplyInPlace(image);

                //Create 5x5 matrix using short array
                int rows = 5;
                int cols = 5;
                short[,] Matrix = new short[rows, cols];

                for (int i = 0; i < rows; i++)
                    for (int j = 0; j < cols; j++)
                        Matrix[i, j] = 1;

                //New dilate filter with the 5x5 matrix
                AForge.Imaging.Filters.Dilatation dilate = new AForge.Imaging.Filters.Dilatation(Matrix);
                //Apply the filter
                dilate.ApplyInPlace(image);

                //Save filtered image
                //image.Save("c:\\Rovio\\myHSLImage.png");

                //New blob counter
                AForge.Imaging.BlobCounter detectBlob = new AForge.Imaging.BlobCounter();

                //Get object by size
                detectBlob.ObjectsOrder = AForge.Imaging.ObjectsOrder.Size;

                //Apply BlobCounter
                detectBlob.ProcessImage(image);

                //objects in an array.0
                Rectangle[] rects = detectBlob.GetObjectsRectangles();

                //Create graphics from image
                Graphics g = Graphics.FromImage(image);

                try
                {
                    //Draw rectangle around largest rectangle
                    g.DrawRectangle(new Pen(Color.Red), rects[0]);

                    RecImage(image);

                    return rects[0];

                }
                catch (IndexOutOfRangeException e)
                {
                    //If no blobs return empty rectangle

                    Rectangle r = new Rectangle(0, 0, 0, 0);
                    return r;
                }
            }

And here is my form used to call the controller:

        public partial class MainForm : Form
        {
            public MainForm()
            {
                InitializeComponent();
            }

            private System.Threading.Thread robot_thread;

            private void MainForm_Load(object sender, EventArgs e)
            {
                Rovio.MyRobot robot = new Rovio.MyRobot("", "admin", "");

                //initilise the image view window
                ImageViewer source_view = new ImageViewer();
                source_view.Text = "Source";
                source_view.Show();
                //attach the robot event to the image update method
                robot.RecImage += source_view.UpdateImage;
                robot.Bangbang();

                //repeat the above code to visualise other steps of your image processing algorithm
                //for example
                //ImageViewer grayscale_view = new ImageViewer();
                //grayscale_view.Text = "Grayscale";
                //grayscale_view.Show();
                //robot.GrayscaleImage += grayscale_view.UpdateImage;

                //ImageViewer rectangle_view = new ImageViewer();
                //rectangle_view.Text = "Rectangle";
                //rectangle_view.Show();
                //robot.RectangleImage += rectangle_view.UpdateImage;

                //create and start the robot thread: your own implementation in MyRobot class
                robot_thread = new System.Threading.Thread(new System.Threading.ThreadStart(robot.ProcessImages));
                robot_thread.Start();
            }

Really need the help on this! Thanks again.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.