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
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.
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.
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;
}
}
}
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:
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.
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;
}
}
}
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.
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;
}
}
}
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