![]() ![]() |
May 30 2007, 02:39 PM
Post
#1
|
|
|
Newbie ![]() Group: Members Posts: 3 Joined: 30-May 07 Member No.: 2,351 |
Hi,
I've read some of the previous posts on parallel- tasks (concurrent/multi-threaded), but I'm still not quite sure how to use them. What I am working on is a robot for sumo. The light-sensor points downwards to detect the edge of the circle (the playing-field-boundary). The ultrasonic-sensor (US) points forward to detect the opponent. I want the robot to move around searching for the opponent using the US-sensor. But, if the light-sensor detects the edge of the circle, the searching activity should be "interrupted", and the robot should retreat back into the playing field. So, I am wondering, if the light-sensor (edge-detecting) and US-sensor (searching) activities are in concurrent tasks, how can I make the light-sensor "override" the searching task? So, the light-sensor-task should take control over the motors only if the circle-edge is detected. Thanks for any help. |
|
|
|
May 30 2007, 02:44 PM
Post
#2
|
|
![]() Advanced Member ![]() ![]() ![]() Group: Moderators Posts: 483 Joined: 6-July 06 Member No.: 29 |
Have the 'searching' task continously monitor some 'state' variable, which can either be 'inside arena' or 'on the edge'. When it sees the later state, it stops/switches to alternative task 'avoiding falling out'
|
|
|
|
May 31 2007, 11:09 AM
Post
#3
|
|
|
Newbie ![]() Group: Members Posts: 3 Joined: 30-May 07 Member No.: 2,351 |
Have the 'searching' task continously monitor some 'state' variable, which can either be 'inside arena' or 'on the edge'. When it sees the later state, it stops/switches to alternative task 'avoiding falling out' Hi Golem, Thank you for the tips on strategy and algorithm. :-) I forgot to say in my post that I am referring on how to use NXC. Basically, I'm a little confused on how to use the concurrency abilities of NXC. Can one task "interrupt" another task? I'm more focused on learning about NXC - the sumo example is more of an illustration. Thanks again :-) |
|
|
|
May 31 2007, 11:55 AM
Post
#4
|
|
![]() Advanced Member ![]() ![]() ![]() Group: Moderators Posts: 2,045 Joined: 8-July 06 Member No.: 37 |
Can one task "interrupt" another task? The short answer is "No". The slightly longer answer is still "No, but you can make your tasks monitor something so they know when to change behavior". In other words, have the tasks watch a variable as a semaphore that can be set by other parrallel tasks. There are some tricks you can do that look closer to an interrupt-driven system, by using FW-level tasks that can be immediately "redirected". Here's an example in NXT-G: State-based "prompt interrupt" system -- Brian Davis |
|
|
|
Jun 1 2007, 03:06 PM
Post
#5
|
|
|
Newbie ![]() Group: Members Posts: 3 Joined: 30-May 07 Member No.: 2,351 |
Thank you for the info Brian. I'll try out your NXT-G program. :-) |
|
|
|
Jun 11 2007, 07:15 PM
Post
#6
|
|
|
Member ![]() ![]() Group: Members Posts: 23 Joined: 4-February 07 From: Murder Capital of Canada (Deadmonton, AB) Member No.: 1,183 |
Hi, I've read some of the previous posts on parallel- tasks (concurrent/multi-threaded), but I'm still not quite sure how to use them. What I am working on is a robot for sumo. The light-sensor points downwards to detect the edge of the circle (the playing-field-boundary). The ultrasonic-sensor (US) points forward to detect the opponent. I want the robot to move around searching for the opponent using the US-sensor. But, if the light-sensor detects the edge of the circle, the searching activity should be "interrupted", and the robot should retreat back into the playing field. So, I am wondering, if the light-sensor (edge-detecting) and US-sensor (searching) activities are in concurrent tasks, how can I make the light-sensor "override" the searching task? So, the light-sensor-task should take control over the motors only if the circle-edge is detected. Thanks for any help. Hey there! Well as I am the State based guy I figured I would throw in a few lines to see if I can help. It sounds like you are trying to figure out how to use concurrent tasks here? First you have to specify the task. In the case that you have presented I can see 3 concurrent tasks. One to monitor the lSensor, one to Monitor the US sensor and one to control the movement of the robot. Create your tasks using the 'task taskname()' and can start them concurrently in your 'precedes(taskname1, taskname2, taskname3);'. If you want you can also start tasks by using the 'start taskname();' command. The issues here are when two tasks attempt to control the same input, (US and lSensor) or output (motors) at the same time. You can get some screwy issues. NXC provides what they call a MUTEX variable to help handle this. Mostly this is used by the motors and is simply a flag that says "I have control" of a certain function. I am not the best person to ask regarding using the MUTEX varible as when you use a statebased methodology they aren't really nessisary. First you have to figure out the various actions that your robot can take and assign a state to them. This can get awfully complex and can include global and local states. I define a 'global' state as a state value that other processes and tasks are monitoring and a local state and one that is only valid in a particular task or process. Right now I am only using global states and will be getting more into local states later. So lets say your robot does four basic things plus STOP. That means we need five states; 0 - STOP 1 - Move Forward 2 - Turn Left 3 - Turn Right 4 - Move Backward So set a global varible to hold the state (I like to use one called State =P). This SHOULD be an unsigned integer or a REAL number but a INT declaration will do. Now the big change from what you are used to is simply one of logic. Lets say we want to robot to move forward until it reached a dark surface (Threshold < 40). We could do this two ways; CODE #include "NXCdefs.h" int Threshold = 40; int lSensor; task main() { SetSensorLight(S3); lSensor = Sensor(S3); while (Threshold < lSensor0) { OnFwdReg(OUT_BC, MotorSpeed, OUT_REGMODE_SPEED); } Off(OUT_BC); } As you can see the code is pretty basic and doesn't really require a state based solution. It is good for demonstration purposes, however. So in this bit of code, what are the actions the robot takes? Well there are two. 1) Move forward and 2) Stop. These can be our states and are set as follows; 0 = Move forward 1 = Stop So lets see how the state based version of the same program will work. CODE #include "NXCdefs.h" int State; int Threshold; int lSensor; task SensorMon() { SetSensorLight(S3); while (true) { lSensor = Sensor(S3); if (lSensor > Threshold) { State = 0; } else { State = 1; } } } /* above we have our Sensor monitor and state controller. Because State in this program is dependent on the lSensor Value, this determines our control structure. It activates the sensor and starts a loop. If the statement is true, and a dark surface is found, it sets the state to 1 or STOP. If no dark surface is found then set the state to 0 or Move Forward. It continually evaluates this condition. From here we could either make up two tasks, our motor control task and our main() task. In this case main() could handle both fuctions, however we are looking at concurrency so we may as well go all in */ task MotorControl() { while(true) { while(State == 0) { OnFwdReg(OUT_BC, MotorSpeed, OUT_REGMODE_SPEED); // Move forward if state == 0 } while(State == 1) { Off(OUT_BC); // Stop if state == 1 } } } /* As you can see, in this program the MotorControl task only cares about the state. Because only one state is active at a time we can be sure we aren't generating a conflict. The SensorMon task controls what the state is. Now we only have to create our task main() and start our two tasks */ task main() { precedes(SensorMon, MotorControl) } So that is a basic overview of state based methodology and concurrent tasks. Or my implementation of them at least. I like to also add in a variable called PreviousState. This allows me to nest states and can allow for some more complex actions as you can evaluate the next step based not only on what the robot is doing currently, but also what the last action it took was. It may seem like a more complex way of programming, but that is only because this is a very simple program that I am using for demonstration purposes. Be careful to think out all your possible states. You might want to set up a graph that lists all the posible combinations of State and PreviousState and then insure that you program a action for each result. I hope that helps! I should be putting this up on my blog soon and going into this type of programming in depth as I work on my own project. If you have questions, give me a shout! TTYL -------------------- |
|
|
|
Dec 30 2008, 01:17 PM
Post
#7
|
|
|
Newbie ![]() Group: Members Posts: 1 Joined: 29-December 08 Member No.: 6,579 |
Just a quick message to thank all of you guys: you are *awesome*!
I just got my NXT a few days ago as a Christmas gift and after building the Tribot I started to look around for more info about coding. I discovered this forum yesterday and there is such a wealth of information here that I learned a lot just by reading the posts. I was getting ready to ask about how to write interrupt driven programs in NXT-G and/or NXC when I found this post. Awesome, really, both NXT-G and NXC covered! Now I just have to figure out how to "implement" Brian's image in a real app. Anyway, like I said, this message has one purpose only: a big THANK YOU! to all of you: with the info you post and blogs you maintain, you make things so much easier for beginners like me. Thank you so much! |
|
|
|
Dec 31 2008, 02:10 AM
Post
#8
|
|
![]() Captain Oblivious ![]() ![]() ![]() Group: Members Posts: 887 Joined: 23-February 08 From: Rotterdam, The Netherlands Member No.: 4,793 |
The robotic behaviour you are looking to implement is also known as "subsumption", where one type of behaviour can override another. I found some really good articles on it when I was looking to implement a very simple subsumption engine for my robot.
On the IBM website: http://www.ibm.com/developerworks/java/library/j-robots/ And a paper: http://www.transterpreter.org/papers/simps...ud-cpa-2006.pdf Also, here is my rather simplistic program, written in RobotC, but should be quite portable to NXC. There are two behaviours in this program, "go straight" and "avoid". The first is the default behaviour and controls the robot if there is nothing overriding it. The avoid task continuously checks if is nothing in its way and will remain inactive as long this the case. However, should something be detected, it will flag itself as active. The main task will see this and send the "go forward" task a signal that it is now inhibited, or overriden. The avoid task can now do what it does best, and avoid the object in its path by turning the robot. After a 400ms timeout, the "avoid" task becomes inactive again, allowing the "go forward" behaviour to be dis-inhibited (for lack of a better word). This kind of simplistic behaviour is great for robots like a sumo. You might not realise it, but the Roomba robotic vacuum cleaner, uses the very same behavour based system, albeit a little more complex. Your sumo might include behaviours like "avoid edge", "charge enemy" and "roam". You will need to figure out which behaviour overrides which. The code for my simple robot is below. My apologies for the lack of comments, I put it together rather quickly and mostly for myself. I hope my explanation above will help you understand it a bit. CODE #pragma config(Sensor, S1, sonar, sensorSONAR) //*!!Code automatically generated by 'ROBOTC' configuration wizard !!*// #define NUMTASKS 2 #define AVOID_TMOUT 400 void moveForward(); void turnRobot(); int ubyteToInt(ubyte _byte); typedef enum { GO_STRAIGHT = 0, TURN_ROBOT = 1 } tMotorCommand; tMotorCommand motorCommand; byte override[NUMTASKS][NUMTASKS] = {{0, 0}, {1, 0}}; byte active[NUMTASKS]; byte inhibited[NUMTASKS]; // This function allows conversion of an unsigned byte to a signed int. // This is a work-around for RobotC bug entry 222 // http://www.education.rec.ri.cmu.edu/tools/...view.php?id=222 int ubyteToInt(ubyte _byte) { int _tmp = (_byte & 0x80) ? (_byte & 0x7F) + 0x80 : _byte; return _tmp; } void moveForward() { if (nSyncedMotors != synchBC) nSyncedMotors = synchBC; nSyncedTurnRatio = 100; motor[motorB] = 75; } void turnRobot() { if (nSyncedMotors != synchBC) nSyncedMotors = synchBC; nSyncedTurnRatio = -100; motor[motorB] = 20; } task goforward () { byte _task_id = 0; while (true) { active[_task_id] = 1; if (!inhibited[_task_id]) { motorCommand = GO_STRAIGHT; } } } task avoid () { bool _avoiding = false; byte _task_id = 1; while (true) { if (SensorValue[sonar] < 30) { time1[T1] = 0; _avoiding = true; active[_task_id] = 1; } else if (time1[T1] > AVOID_TMOUT) { _avoiding = false; active[_task_id] = 0; } if (!inhibited[_task_id]) { motorCommand = TURN_ROBOT; } } } task controlMotor () { while (true) { switch(motorCommand) { case GO_STRAIGHT: moveForward(); break; case TURN_ROBOT: turnRobot(); break; } } } task main () { byte _currTask = 0; byte _currOverride = 0; byte _tmp_inhibited[NUMTASKS]; memset(_tmp_inhibited[0], 0, NUMTASKS); memset(active[0], 0, NUMTASKS); nSyncedMotors = synchBC; StartTask(goforward); StartTask(avoid); StartTask(controlMotor); while (true) { memset(_tmp_inhibited[0], 0, NUMTASKS); for (_currTask = 0; _currTask < NUMTASKS; _currTask++) { if (!active[_currTask]) { _tmp_inhibited[_currTask] = 1; } else { for (_currOverride = 0; _currOverride < NUMTASKS; _currOverride++) { _tmp_inhibited[_currTask] += active[_currOverride] * override[_currOverride][_currTask]; } } } memcpy(inhibited[0], _tmp_inhibited[0], NUMTASKS); eraseDisplay(); for (_currTask = 0; _currTask < NUMTASKS; _currTask++) { nxtDisplayTextLine(_currTask, "0: %d, %d", ubyteToInt(active[_currTask]), ubyteToInt(inhibited[_currTask])); } } } Enjoy! Xander -------------------- | What the world needs is more geniuses with humility, there are so few of us left.
| Current projects and ramblings: I'd Rather Be Building Robots | RobotC 3rd Party Driver Suite: [Project Page] / [API Documentation] |
|
|
|
Jan 4 2009, 07:41 PM
Post
#9
|
|
![]() Advanced Member ![]() ![]() ![]() Group: Moderators Posts: 2,045 Joined: 8-July 06 Member No.: 37 |
Anyway, like I said, this message has one purpose only: a big THANK YOU! to all of you: with the info you post and blogs you maintain, you make things so much easier for beginners like me. Thank you so much! You are more than welcome. It doesn't matter a lot here what language or firmware you're using... it seems you can usually find something or someone to help. Welcome to the group -- Brian Davis |
|
|
|
![]() ![]() |
| Lo-Fi Version | Time is now: 9th February 2010 - 04:44 PM |