As it stands, my code seems needlessly spread out among classes. I'm not an experienced programmer yet, but I'm trying to "future proof" my project thinking that I may add a lot more to the code as time goes on and separating it all now is better than later.
What should happen: The robot should approach some obstacle like a wall. Once closer than 20 (cm?) it should stop. Then it will turn left, scan for distance: if distance is greater than 50(cm?) move forward. Else, then Turn 180 degrees (a right turn from the original stopped position), scan for distance: if distance is greater than 50 move forward. Else, turn 90 degrees right (180 degrees from original stopped position), scan for distance: if distance is greater than 50 move forward.
(If that is false, the robot just sits in place "broken" so to speak. I'm okay with that for now)
What actually happens: The robot approaches a wall, and when closer than 20 it stops. It turns left, then always turns 180 around. Then always turns right, then always stops and sits there. Waving my hand in and out from the sensor afterward has no effect.
It seemingly is unable to detect any walls during the turning portion, however is able to detect walls while in motion at the start of the program.
Class description/explanation:
The SonicSensor class (_ss) implements FeatureListener and is registered with the RangeFeatureDetector. I use this to constantly check distances up to length 100 (is this cm?)
It calls a secondary method 'getDistance()' I created, which simply calls the UltrasonicSensor's getDistance() method but with a 50ms Thread.sleep before returning the value.
MotionLogic (_ml) is where the project makes the decisions utilizing data from other classes. The method call 'checkDistance' decides if the robot is too close and needs to stop.
- Code: Select all
public class SonicSensor implements FeatureListener{
private UltrasonicSensor _us;
private FeatureDetector _fd;
private MotionLogic _ml;
public SonicSensor(UltrasonicSensor us, FeatureDetector fd, MotionLogic ml)
{
_us = us;
_fd = fd;
_fd.addListener(this);
_ml = ml;
}
@Override
public void featureDetected(Feature feature, FeatureDetector detector)
{ _ml.checkDistance(getDistance()); } //checks distance, and sets _distance value in MotionLogic iff object is detected in front
public int getDistance()
{
int d = _us.getDistance();
try { Thread.sleep(50); }
catch(InterruptedException ex) {}
return d;
}
}
The next code is from MotionLogic, I'm leaving out the constructor as it's lengthy.
MotionControls (_mc) is full of methods that define the robot's movements, a couple of calls are made to that in the following.
checkDistance(int distance) decides if the robot is too close and should take action. If it is, it calls the method avoid()
This part works properly with the robot. It does stop when it gets too close to a wall. Meaning it makes a correct evaluation of distance, and in fact calls 'avoid()' and executes the first line (at least) of 'avoid()'
The lines following that don't seem to give the desired effect.
- Code: Select all
public class MotionLogic {
public void checkDistance(int distance) //_fd will not start report unless an object is detected.
//That is, if nothing is within range, it will not trigger checkDistance()
{
_distance = distance;
if(_distance < 20) { avoid(); }
else { _mc.forward(); }
}
public void avoid()
{
_mc.stop(); //stop wheels
_fd.enableDetection(false); //prevents call to checkDistance(). _range will still be updated
_mc.turnLeftInPlace90();
if(_ss.getDistance() > 50) { _fd.enableDetection(true); return; } //restarts checkDistance call and breaks method.
_mc.turnRightInPlace180(); //equivalent of a right turn from original position
if(_ss.getDistance() > 50) { _fd.enableDetection(true); return; }
_mc.turnRightInPlace90(); //equivalent of 180 turn from original position
if(_ss.getDistance() > 50) { _fd.enableDetection(true); return; }
//Need a final alternative if the first 3 fail?
}
public void setRange(int range) //I guess I'll keep this so other classes can manipulate this value. Perhaps to 'trick' this class.
{ //_mc has getRange() accessor for most other purposes though.
_distance = range;
}
}
I disabled the RangeFeatureDetector while the code is turning the robot. My thought is that having it constantly detect objects could cause conflicts like trying to call avoid() twice or something.
I set this up so I don't need it though. The second method in SonicSensor 'getDistance' isn't (as far as I understand it) a part of the RangeFeatureDetector and can be called at any time.
Remember how I said "Waving my hand in and out from the sensor afterward has no effect." at the top? Well if I switch my > symbols, waving my hand in and out from the sensor will cause the robot to begin moving forward again after doing all his turns and coming to a halt. It does NOT change any of the previous outcomes of the program.
To determine this wasn't an issue with disabling/enabling the FeatureDetector, I tried adding a _mc.forward() method call inside the if() brackets.
This would mean that even the last one should be called (it came from a direction with no object behind him) and detect no object, returning a distance of 255 (distance() returns 255 if nothing is seen). Regardless if FeatureDetector became broken from the disabling, or it won't trigger checkDistance() because it can't see anything, the robot should move forward.
But it does not.
So the issue seems to be with the SonicSensor returning a proper distance. Or in the distance() method returning values I'm not anticipating.
But then again, this works just fine in checkDistance()
What's worse, I actually had this working before, but after making a bunch of changes to other classes, I started getting the issue I'm describing now.
I quite honestly have no idea what the code was like before, I made a lot of changes. But I really, truly, honestly made no changes to the code in avoid() which is why I'm so surprised and frustrated that it's giving me problems now
I hope my short novel gave you enough information to help me
