/unige-rt1-assignment1

Using the Python Robotics Simulator developed by Student Robotics to make a robot do stuff in an environment.

Primary LanguagePythonOtherNOASSERTION

Research Track 1 - Assignment 1 (UniGe)

The assignment contains two main branches:

  • This branch, master, contains the code for the first assignment of the course "Research Track 1"
  • The branch rt2_analysis contains the code for the second assignment of the course "Research Track 2", which is the statistical analysis based on performance of different implementations in a randomized token arena.

=======================================

About Python Robotics Simulator

This is a simple, portable robot simulator developed by Student Robotics. Some of the arenas and the exercises have been modified for the Research Track I course

Installation

The simulator requires a Python 2.7 installation, the pygame library, PyPyBox2D, and PyYAML.

Pygame, unfortunately, can be tricky (though not impossible) to install in virtual environments. If you are using pip, you might try pip install hg+https://bitbucket.org/pygame/pygame, or you could use your operating system's package manager. Windows users could use Portable Python. PyPyBox2D and PyYAML are more forgiving, and should install just fine using pip or easy_install.

To run the project, it is recommended to create a python2 virtualenv for the project. To do so, we first need to install virtualenv pip package, and then create a python2.7 virtualenv since the simulator is based on python2.7:

$ pip install virtualenv
$ git clone https://github.com/amanarora9848/unige-rt1-assignment1.git
$ cd unige-rt1-assignment1
$ virtualenv -p /usr/bin/python2.7 .rt1project1
$ . .rt1project1/bin/activate

This activated the python2.7 virtualenv. To deactivate:

$ deactivate

Once in the venv, we can install the project requirements. Fortunately, there exists a requirements.txt file.

$ pip install -r requirements.txt

Troubleshooting

When running python run.py <file>, you may be presented with an error: ImportError: No module named 'robot'. This may be due to a conflict between sr.tools and sr.robot. To resolve, symlink simulator/sr/robot to the location of sr.tools.

On Ubuntu, this can be accomplished by:

  • Find the location of srtools: pip show sr.tools
  • Get the location. In my case this was /usr/local/lib/python2.7/dist-packages
  • Create symlink: ln -s path/to/simulator/sr/robot /usr/local/lib/python2.7/dist-packages/sr/

Note:

The robot might (in rare cases) appear stopped, but actually it be turning in opposite directions very fast and could take a couple of moments until it reorients itself correctly and finds the token. In such cases, please patiently wait for it to move fast again, it will.

The Exercise


To run the scripts in the simulator, use run.py, passing to it the file names.

$ python run.py assigment.py

Short video of task in action

Robot API

The API for controlling a simulated robot is designed to be as similar as possible to the SR API.

Motors

The simulated robot has two motors configured for skid steering, connected to a two-output Motor Board. The left motor is connected to output 0 and the right motor to output 1.

The Motor Board API is identical to that of the SR API, except that motor boards cannot be addressed by serial number. So, to turn on the spot at one quarter of full power, one might write the following:

R.motors[0].m0.power = 25
R.motors[0].m1.power = -25

The Grabber

The robot is equipped with a grabber, capable of picking up a token which is in front of the robot and within 0.4 metres of the robot's centre. To pick up a token, call the R.grab method:

success = R.grab()

The R.grab function returns True if a token was successfully picked up, or False otherwise. If the robot is already holding a token, it will throw an AlreadyHoldingSomethingException.

To drop the token, call the R.release method.

Cable-tie flails are not implemented.

Vision

To help the robot find tokens and navigate, each token has markers stuck to it, as does each wall. The R.see method returns a list of all the markers the robot can see, as Marker objects. The robot can only see markers which it is facing towards.

Each Marker object has the following attributes:

  • info: a MarkerInfo object describing the marker itself. Has the following attributes:
    • code: the numeric code of the marker.
    • marker_type: the type of object the marker is attached to (either MARKER_TOKEN_GOLD, MARKER_TOKEN_SILVER or MARKER_ARENA).
    • offset: offset of the numeric code of the marker from the lowest numbered marker of its type. For example, token number 3 has the code 43, but offset 3.
    • size: the size that the marker would be in the real game, for compatibility with the SR API.
  • centre: the location of the marker in polar coordinates, as a PolarCoord object. Has the following attributes:
    • length: the distance from the centre of the robot to the object (in metres).
    • rot_y: rotation about the Y axis in degrees.
  • dist: an alias for centre.length
  • res: the value of the res parameter of R.see, for compatibility with the SR API.
  • rot_y: an alias for centre.rot_y
  • timestamp: the time at which the marker was seen (when R.see was called).

For example, the following code lists all of the markers the robot can see:

markers = R.see()
print "I can see", len(markers), "markers:"

for m in markers:
    if m.info.marker_type in (MARKER_TOKEN_GOLD, MARKER_TOKEN_SILVER):
        print " - Token {0} is {1} metres away".format( m.info.offset, m.dist )
    elif m.info.marker_type == MARKER_ARENA:
        print " - Arena marker {0} is {1} metres away".format( m.info.offset, m.dist )

Working and Explanation

The main python script: assignment22.py

This file is for executing the procedure for the assignment. Given the robot, the environment and the defined parameters, the task for the robot is to pick and place each nearest silver token near the nearest golden one at a given instant of time.

The robot starts with searching the silver token, which is defined when 'engage' control flag is True. The robot finds the nearest silver flag and moves towards it. Everytime the silver token is grabbed, the engage flag is inverted to search and move towards the nearest gold flag. Everytime the silver token is released, the engage flag is again inverted. The function definitions and logic is defined in the pseudocode below.

Once the task is finished, the robot rejoices.

Variables and "switches"

The code has following variables which control different aspects of the overall execution, as stated in the comments:

a_th = 2.0
""" float: Threshold for the control of the orientation """

silver_th = 0.40 # Threshold distance for silver (nearest distance to approach before action).
gold_th = 0.62  # Threshold for gold, slightly more.
""" float: Thresholds for the control of the linear distance to a silver or gold token """

engage = True # Starting with silver who uses this flag first, and then is given to gold.

total_tokens = 12 # Total number of tokens (should be evenfor this task)

want_dynamic_speed = True # Preference for dynamic or static speed settings for the robot

not_seen_flag = done_flag = already_seen_flag = unmoved_flag = moveback_flag = False

The variables silver_th and gold_th control the minimum distance of approach to respective token, and gold has a higher value, unsurprisingly, because the silver token has to be released in front of the gold token without pushing it. Variable a_th defines the same thing, just for the orientation of the robot w.r.t token.

The toggle engage toggles everything concerning with the silver/gold token. Functions taking this flag gather information and execute instructions of search, grab and release based on this flag. engage being True is silver, and opposite is gold.

total_tokens is a variable which holds the number of tokens in the environment, and the code takes this into account and stops when all tokens have been arranged. This is kept for a possible future improvement wherein we can take input from user or other source regarding number of elements (even).

want_dynamic_speed is an option that the user can choose to keep True (if they want smoother motion of robot, the robot drive and turn speeds vary with variations in the distance or orientation from the token being searched), or want the speeds to be static i.e. False.

Finally, variables not_seen_flag to moveback_flag are used to control the printing procedures (for appropriate print statements and printing them once per condition).

Functions and Procedures

Following functions are used to drive the robot around and perform the task requested.

1. PROCEDURE drive: Function for setting a linear velocity
2. PROCEDURE turn : Function for setting an angular velocity
3. FUNCTION locate_token : Function to find the closest silver or gold token, based on the passed control flag. Returns a dictionary "token_information" with keys as follows - distance, orientation, token_code, token_color, distance_threshold.
4. PROCEDURE drive_to_deliver : Function to drive robot towards the token.
5. PROCEDURE continue_search : Function to rotate robot and make it keep searching for the next token.
6. PROCEDURE grab_release : Function to grab the nearest seen silver token and release it near the nearest seen gold token.
7. PROCEDURE end_task : Function for the robot to stop the task and end program execution after completion.

PROCEDURE: Arrange all silver-gold tokens in pairs.

SELECTOR //BOOLEAN, True means wanted token is silver, False means wanted token is gold
SILVER_ARRANGED //set of silver tokens already dealt with
GOLD_ARRANGED //set of gold tokens already dealt with

procedure MAIN()

    token_info  LOCATE_TOKEN(SELECTOR)

    if no token detected
        keep searching

    else if all tokens arranged
        end execution

    else if token observed has required color and has already been arranged
        keep searching
    
    else
        if token_info[distance] < token_info[distance_threshold_for_current_color_token]
            if SELECTOR is True
                grab token
                ADD token to SILVER_ARRANGED
            else
                release token
                ADD token to GOLD_ARRANGED
                drive robot backwards
            endif
            invert SELECTOR
        endif

        //maneuver robot to wanted token
        if token_info[orientation] > orientation_threshold:
            turn robot right
        else if token_info[orientation] < -orientation_threshold:
            turn robot left
        else if token_info[orientation] <= |orientation_threshold|
            drive robot forward
        endif
    
    endif

Possible Improvements

  • For the case of a silver obstacle in the path of the robot while it has already grabbed a silver token, logic to go around it instead of colliding with it can be written.

  • User input to set the driving and turning speed of the robot can be accepted and integrated into the code.

  • The movement of the robot can be made smoother by calculating appropriate gain for accuracy and adding (or reducing) small amount of "power" on every iteration upto a desired value, instead of setting it to desired value, and the execution time can be reduced. However, this method was observed to be a little prone to errors, so skipped for now.

  • There could be more precision in how close to the gold token does the robot drop the silver token.

  • The current code logic could be made even simpler.