Main Site Documentation

Line follower+ collision avoidance


#1

Hello all

I applied the line follower in FEZ cerbot and it is working. However, I need to add a collision avoidance by using a distance module
They work well separately but could not figure out how to combine them in one project solution.
I used two threads but one of them worked at a time, please help


#2

Welcome to the forum.

You can copy the code from one project to another or use one project as a class library.
Is that where you have the problem?


#3

@ Architect -

Thank you for the quick response
we already copied the collision avoidance code to the line follower solution. However, the problem is a logical error because only one code is working at a time.


#4

Can you show your code?


#5

When using two threads, each containing a Loop, then you Need to have an appropiate Thread.Sleep() in each thread. By this the Scheduler can run both threads.
And as @ Archtict mentioned: seeing your code would help.


#6

we added thread.sleep for both loops but nothing is working now
we tried to combine the codes for collision avoidance and line follower from codeshare which are located at these links
https://www.ghielectronics.com/community/codeshare/entry/846
https://www.ghielectronics.com/community/codeshare/entry/897

here is the code we used :

using System;
using System.Collections;
using System.Threading;
using Microsoft.SPOT;
using Microsoft.SPOT.Presentation;
using Microsoft.SPOT.Presentation.Controls;
using Microsoft.SPOT.Presentation.Media;
using Microsoft.SPOT.Presentation.Shapes;
using Microsoft.SPOT.Touch;

using Gadgeteer.Networking;
using GT = Gadgeteer;
using GTM = Gadgeteer.Modules;
using Gadgeteer.Modules.GHIElectronics;

namespace thread222
{
    public partial class Program
    {
        const int MaxSpeed = 95;                            // Maximum speed that the motors can turn at
        const int Speed = 90;                               // Default speed for the Cerbot
        const int Acceleration = 5;                         // Acceleration rate for turning
        const int Deceleration = 1;                         // Deceleration rate for turning, used for oposite motor
        const int MaxAcceleration = MaxSpeed - Speed;       // Max acceleration that can be applied without exceeding the motor speed
        const int MinAcceleration = -(MaxSpeed + Speed);    // Max acceleration that can be applied without exceeding the motor reverse speed
        const int ReflectionThreshold = 50;                 // Reflection sensor threshold below which the Cerbot will react
        // This method is run when the mainboard is powered up or reset.   
        void ProgramStarted()
        {
           
            Debug.Print("Program Started");
            new Thread(DoEdgeDetect).Start();
            new Thread(linefollower).Start();
        }
        void DoEdgeDetect()  //does edge detect and distance with US3
        {

            const int RUN_SPEED = 70;
            const int REVERSE_SPEED = -70;
            distance_US3.AcceptableErrorRate = 0;
            int j;
            const double SENSOR_THRESHOLD = 10;

            while (true)
            {
                Thread.Sleep(1);

                bool leftOverEdge = cerbotController.GetReflectiveReading(CerbotController.ReflectiveSensors.Left) > SENSOR_THRESHOLD;
                bool rightOverEdge = cerbotController.GetReflectiveReading(CerbotController.ReflectiveSensors.Right) > SENSOR_THRESHOLD;

                if (!rightOverEdge && !leftOverEdge)
                {

                    //if it detects edges, stops
                    cerbotController.SetMotorSpeed(0, 0);
                    cerbotController.StartBuzzer(1000, 100);
                    Thread.Sleep(2000);
                }

                else
                {
                    Thread.Sleep(100);

                    j = distance_US3.GetDistanceInCentimeters(5);

                    if (j <= 5 || j >= 40)
                    {
                        cerbotController.SetMotorSpeed(RUN_SPEED, RUN_SPEED);

                    }
                    else
                    {

                        //if it detects object within 40 centimetes, stops, backs up, turns, beeps then goes forward

                        cerbotController.SetMotorSpeed(0, 0);
                        cerbotController.SetMotorSpeed(REVERSE_SPEED, REVERSE_SPEED);
                        Thread.Sleep(250);
                        cerbotController.SetMotorSpeed(REVERSE_SPEED, RUN_SPEED);
                        Thread.Sleep(500);
                        cerbotController.SetMotorSpeed(0, 0);
                        cerbotController.StartBuzzer(2000, 500);
                        cerbotController.SetMotorSpeed(RUN_SPEED, RUN_SPEED);

                    }
                }


                Thread.Sleep(2000);
            }
        }
        void linefollower()
        {
            // Prepare for the main loop driving the cerbot
            int leftAcceleration = 0;
            int rightAcceleration = 0;
            bool adjustSpeed = true;
            while (true)
            {
                // Check if an adjustment is required for the motors
                if (adjustSpeed)
                {
                    // Adjust the motors
                    cerbotController.SetMotorSpeed((int)(Speed + leftAcceleration), (int)(Speed + rightAcceleration));
                    adjustSpeed = false;
                }

                // Read the sensors
                var leftSensor = cerbotController.GetReflectiveReading(CerbotController.ReflectiveSensors.Left);
                var rightSensor = cerbotController.GetReflectiveReading(CerbotController.ReflectiveSensors.Right);

                if (leftSensor < ReflectionThreshold && rightSensor >= ReflectionThreshold)
                {
                    // Only the left scensor has limited reflectivity, so
                    // we speed-up the right motor and slow the left motor
                    rightAcceleration += Acceleration;
                    leftAcceleration -= Deceleration;
                    adjustSpeed = true;
                }
                else if (System.Math.Abs(leftAcceleration) > 0)
                {
                    // Remove all acceleration from the left motor
                    leftAcceleration = 0;
                    adjustSpeed = true;
                }

                if (rightSensor < ReflectionThreshold && leftSensor >= ReflectionThreshold)
                {
                    // Only the right scensor has limited reflectivity, so
                    // we speed-up the left motor and slow the right motor
                    leftAcceleration += Acceleration;
                    rightAcceleration -= Deceleration;
                    adjustSpeed = true;
                }
                else if (System.Math.Abs(rightAcceleration) > 0)
                {
                    // Remove all acceleration from the right motor
                    rightAcceleration = 0;
                    adjustSpeed = true;
                }

                // Ensure that we do not exceed the acceleration thresholds that would
                // push the motors past the speed limit
                leftAcceleration = ClampAcceleration(leftAcceleration);
                rightAcceleration = ClampAcceleration(rightAcceleration);
                Thread.Sleep(2000);
            }
        }
              private int ClampAcceleration(int acceleration)
        {
            return acceleration > MaxAcceleration ? MaxAcceleration : acceleration < MinAcceleration ? MinAcceleration : acceleration;
        }
        }
    }

please help


#7

Have you checked if you get any exceptions.
I also don’t know if the cerbotController is thread safe: means if a parallel access from 2 threads might cause the trouble.
But this is easy solvable:
put a lock around the cerbotController code like this:

...
lock(cerbotController)
{
   bool leftOverEdge = cerbotController.GetReflectiveReading(CerbotController.ReflectiveSensors.Left) > SENSOR_THRESHOLD;
   bool rightOverEdge = cerbotController.GetReflectiveReading(CerbotController.ReflectiveSensors.Right) > SENSOR_THRESHOLD;
}
...
lock(cerbotController)
{
   var leftSensor = cerbotController.GetReflectiveReading(CerbotController.ReflectiveSensors.Left);
   var rightSensor = cerbotController.GetReflectiveReading(CerbotController.ReflectiveSensors.Right);
}
...

add locks like these everywhere you use cerbotController


#8

@ Reinhard Ostermeier
thank you for your help and time

I added lock (cerbotController) everywhere I used cerbotController but still nothing is working neither line follower nor collision avoidance

all it did was turning left without even avoiding objects

any other ideas


#9

I would try to do line following and edge detection in one loop/thread.


#10

yes I think your algorithm won’t work when you have two threads fighting to control what is essentially the same observations. You’ll need to blend the two approaches.

Also, in testing you don’t really tell us what debugging of the processing you did ? What triggered the left turn for example, was it the line follower or the edge detection thread ?

And you have 2 second sleeps in between passes - I think the earlier suggestion was more likely to be that you needed 20 millisecond sleep so the other thread would be scheduled, 2 seconds seems woefully long between evaluations.


#11

Also i would suggest to set a threads priority… Take a look in google search for netmf threads


#12

Actually I tried to put both codes in one loop/thread and if it detects an object just stop. what happened is that the cerbot moves forward all the time and it did not detect any objects or followed the line.

@ Alex Bilityuk I used threads priority but it did not work as well

here is the code I used (one loop/thread)

using System;
using System.Collections;
using System.Threading;
using Microsoft.SPOT;
using Microsoft.SPOT.Presentation;
using Microsoft.SPOT.Presentation.Controls;
using Microsoft.SPOT.Presentation.Media;
using Microsoft.SPOT.Presentation.Shapes;
using Microsoft.SPOT.Touch;

using Gadgeteer.Networking;
using GT = Gadgeteer;
using GTM = Gadgeteer.Modules;
using Gadgeteer.Modules.GHIElectronics;

namespace thread222
{
    public partial class Program
    {
        const int MaxSpeed = 95;                            // Maximum speed that the motors can turn at
        const int Speed = 90;                               // Default speed for the Cerbot
        const int Acceleration = 5;                         // Acceleration rate for turning
        const int Deceleration = 1;                         // Deceleration rate for turning, used for oposite motor
        const int MaxAcceleration = MaxSpeed - Speed;       // Max acceleration that can be applied without exceeding the motor speed
        const int MinAcceleration = -(MaxSpeed + Speed);    // Max acceleration that can be applied without exceeding the motor reverse speed
        const int ReflectionThreshold = 50;   
         //const int RUN_SPEED = 90;
            const int REVERSE_SPEED = -90;
          
            int j;
        // Reflection sensor threshold below which the Cerbot will react
        // This method is run when the mainboard is powered up or reset.   
        void ProgramStarted()
        {
           
            Thread line = new Thread(linefollower);
             line.Start();

             Debug.Print("Program Started");

        }
       
        void linefollower()
        {
    

            // Prepare for the main loop driving the cerbot
            int leftAcceleration = 0;
            int rightAcceleration = 0;
            bool adjustSpeed = true;
            distance_US3.AcceptableErrorRate = 0;


            while (true)
            {
    
                Thread.Sleep(1);

                        j = distance_US3.GetDistanceInCentimeters(5);

                        if (j <= 5 || j >= 40)
                        {
                            lock (cerbotController)
                            {

                                cerbotController.SetMotorSpeed(Speed, Speed);
                            }

                        }
                        else
                        {

                            //if it detects object within 40 centimetes, stops, backs up, turns, beeps then goes forward

                            lock (cerbotController)
                            {
                                cerbotController.SetMotorSpeed(0, 0);
                            
                            Thread.Sleep(250);
                            }
                }

                // Check if an adjustment is required for the motors
                if (adjustSpeed)
                {
                    // Adjust the motors
                    lock (cerbotController)
                    { cerbotController.SetMotorSpeed((int)(Speed + leftAcceleration), (int)(Speed + rightAcceleration)); }
                    adjustSpeed = false;
                }

                // Read the sensors
                lock (cerbotController)
                {
                    var leftSensor = cerbotController.GetReflectiveReading(CerbotController.ReflectiveSensors.Left);
                    var rightSensor = cerbotController.GetReflectiveReading(CerbotController.ReflectiveSensors.Right);

                    if (leftSensor < ReflectionThreshold && rightSensor >= ReflectionThreshold)
                    {
                        // Only the left scensor has limited reflectivity, so
                        // we speed-up the right motor and slow the left motor
                        rightAcceleration += Acceleration;
                        leftAcceleration -= Deceleration;
                        adjustSpeed = true;
                    }
                    else if (System.Math.Abs(leftAcceleration) > 0)
                    {
                        // Remove all acceleration from the left motor
                        leftAcceleration = 0;
                        adjustSpeed = true;
                    }

                    if (rightSensor < ReflectionThreshold && leftSensor >= ReflectionThreshold)
                    {
                        // Only the right scensor has limited reflectivity, so
                        // we speed-up the left motor and slow the right motor
                        leftAcceleration += Acceleration;
                        rightAcceleration -= Deceleration;
                        adjustSpeed = true;
                    }
                    else if (System.Math.Abs(rightAcceleration) > 0)
                    {
                        // Remove all acceleration from the right motor
                        rightAcceleration = 0;
                        adjustSpeed = true;
                    }
                }

                // Ensure that we do not exceed the acceleration thresholds that would
                // push the motors past the speed limit
                leftAcceleration = ClampAcceleration(leftAcceleration);
                rightAcceleration = ClampAcceleration(rightAcceleration);
                Thread.Sleep(200);
            }
        }
              private int ClampAcceleration(int acceleration)
        {
            return acceleration > MaxAcceleration ? MaxAcceleration : acceleration < MinAcceleration ? MinAcceleration : acceleration;
        }
        }
    }


#13

@ ajma

Single stepping in the debugger will tell you what is happening.

You are not coordinating the detection of an object with the reading of the senors.


#14

You set the motor speed 2 times.
You can not simply put both behaviors in parallel (Threads) or in sequence (one loop).
You need to combine both logics, and then decide what motor speed you set.


#15

Hello

we tried another code that applies both techniques in one thread/loop
the code is basically line follower but if it detects an object, it stops.
we also used SetMotorSpeed for only one time still does not work. it only detected the object (stop) and did not follow the line.

Do you think that the FEZ cerbot does not have the capability to handle both techniques at the same time?

please see the code below

using System;
using System.Collections;
using System.Threading;
using Microsoft.SPOT;
using Microsoft.SPOT.Presentation;
using Microsoft.SPOT.Presentation.Controls;
using Microsoft.SPOT.Presentation.Media;
using Microsoft.SPOT.Presentation.Shapes;
using Microsoft.SPOT.Touch;

using Gadgeteer.Networking;
using GT = Gadgeteer;
using GTM = Gadgeteer.Modules;
using Gadgeteer.Modules.GHIElectronics;

namespace thread222
{
    public partial class Program
    {
        const int MaxSpeed = 95;                            // Maximum speed that the motors can turn at
        const int Speed = 90;                               // Default speed for the Cerbot
        const int Acceleration = 5;                         // Acceleration rate for turning
        const int Deceleration = 1;                         // Deceleration rate for turning, used for oposite motor
        const int MaxAcceleration = MaxSpeed - Speed;       // Max acceleration that can be applied without exceeding the motor speed
        const int MinAcceleration = -(MaxSpeed + Speed);    // Max acceleration that can be applied without exceeding the motor reverse speed
        const int ReflectionThreshold = 50;  
           
        // Reflection sensor threshold below which the Cerbot will react
        // This method is run when the mainboard is powered up or reset.   
        void ProgramStarted()
        {      
             new Thread(() =>
             {

                 // Prepare for the main loop driving the cerbot
                 int leftAcceleration = 0;
                 int rightAcceleration = 0;
                 bool adjustSpeed = true;
                 distance_US3.AcceptableErrorRate = 0;
               //  const int REVERSE_SPEED = -90;
                 int j;

                 while (true)
                 {

                     Thread.Sleep(1);
                     // Check if an adjustment is required for the motors
                     if (adjustSpeed)
                     {
                         // Adjust the motors
                         cerbotController.SetMotorSpeed((int)(Speed + leftAcceleration), (int)(Speed + rightAcceleration));
                         adjustSpeed = false;
                     }

                     j = distance_US3.GetDistanceInCentimeters(5);

                     if (j >= 5 && j <= 40)
                     {
                         cerbotController.SetMotorSpeed(0, 0);
                     }
                     // Read the sensors
                     var leftSensor = cerbotController.GetReflectiveReading(CerbotController.ReflectiveSensors.Left);
                     var rightSensor = cerbotController.GetReflectiveReading(CerbotController.ReflectiveSensors.Right);

                     if (leftSensor < ReflectionThreshold && rightSensor >= ReflectionThreshold)
                     {
                         // Only the left scensor has limited reflectivity, so
                         // we speed-up the right motor and slow the left motor
                         rightAcceleration += Acceleration;
                         leftAcceleration -= Deceleration;
                         adjustSpeed = true;
                     }
                     else if (System.Math.Abs(leftAcceleration) > 0)
                     {
                         // Remove all acceleration from the left motor
                         leftAcceleration = 0;
                         adjustSpeed = true;
                     }

                     if (rightSensor < ReflectionThreshold && leftSensor >= ReflectionThreshold)
                     {
                         // Only the right scensor has limited reflectivity, so
                         // we speed-up the left motor and slow the right motor
                         leftAcceleration += Acceleration;
                         rightAcceleration -= Deceleration;
                         adjustSpeed = true;
                     }
                     else if (System.Math.Abs(rightAcceleration) > 0)
                     {
                         // Remove all acceleration from the right motor
                         rightAcceleration = 0;
                         adjustSpeed = true;
                     }


                     // Ensure that we do not exceed the acceleration thresholds that would
                     // push the motors past the speed limit
                     leftAcceleration = ClampAcceleration(leftAcceleration);
                     rightAcceleration = ClampAcceleration(rightAcceleration);
                     // Thread.Sleep(200);
               
                 }

             }).Start();
             Debug.Print("Program Started");
        }
              private int ClampAcceleration(int acceleration)
        {
            return acceleration > MaxAcceleration ? MaxAcceleration : acceleration < MinAcceleration ? MinAcceleration : acceleration;
        }
        }
    }


#16

the robot is a machine and only as good as your algorithm.

Sure, many people here could read your code and give you pointers. But you have the code and the bot and you can debug it - you have the tools - Visual Studio - to help step through the code and see what your code is telling the robot to do. Find out what is and is not working and work through that. If you think the object is detected then perhaps your sensor (j variable) is something you need to closely monitor in your testing


#17

Fez Cerbot is definitely capable of following a line.
@ taylorza made it balance on two wheels.