RoboCatz.com
About FLL | Navigation | Playbook | Strategy | Models | Techniques | RobotC | Programming | Robot News |

Python Basics

Moving Forward: Example 1

Example below specifies a fixed distance to travel based on the diameter of the wheel. This example uses the .move() method to move for a specified distance. The amount of distance is the first parameter and the units of distance are the second parameter. The units may be centimeters (cm), inches (in), degrees of rotation (deg).

from spike import PrimeHub, MotorPair
from spike.control import wait_for_seconds
import math
import sys

hub = PrimeHub()

motor_pair = MotorPair('B', 'C')                    # Pairs motors on ports B and C
motor_pair.set_motor_rotation(5.7 * math.pi, 'cm')  # Configures the program based on the diameter of the wheel (5.7cm in this case)
driving_speed = -25                                 # In this example the motors were mounted in a way that required negative power to move forward

def driveForward():                                 # Define a function to move forward
    hub.light_matrix.write(driving_speed)           # Display the driving speed
    motor_pair.move(12, 'in', 0, driving_speed)     # Start driving

driveForward()                                      # Move forward
wait_for_seconds(30)                                 # Wait 3 seconds

Moving Forward: Example 2

Example below specifies a fixed distance to travel based on the degrees of rotation using a while loop with a condition specifying the number of degrees. In the while condition the robot is to print the degrees observed to the console window. The .stop() method is required following the while loop. Simply exiting the while loop does not stop the robot by itself. You need to issue the .stop() method to stop the robot.

from spike import PrimeHub, Motor, MotorPair
from spike.control import wait_for_seconds
import math
import sys

hub = PrimeHub()

motor_pair = MotorPair('B', 'C')                    # Pairs motors on ports B and C
motorB = Motor('B')
motor_pair.start(0,-15)
motorB.set_degrees_counted(0)
while motorB.get_degrees_counted() < 360:
    print( motorB.get_degrees_counted())
motor_pair.stop()

Moving Forward: Example 3

Example below specifies a fixed distance to travel based on the degrees of rotation using a while loop with a condition specifying the number of degrees. In the while condition the robot is to print the degrees observed to the console window. The .stop() method is required following the while loop. Simply exiting the while loop does not stop the robot by itself. You need to issue the .stop() method to stop the robot. This example also shows the distance that was traveled by the robot.

from spike import PrimeHub, Motor, MotorPair
from spike.control import wait_for_seconds
import math
import sys

hub = PrimeHub()
wheel_diameter = 2.14                               # Diameter of the wheel in inches
motor_pair = MotorPair('B', 'C')                    # Pairs motors on ports B and C
motorB = Motor('B')                                 # Initialize a variable to keep track of motor B
motor_pair.start(0,-15)                             # Start the motors moving
motorB.set_degrees_counted(0)                       # Reset the encoder value
def drive_forward(inches):                          # Define a function to drive forward
                                                    # The degrees to be turned is a formula using the inches
                                                    # to be traveled and the circumference of the wheel.
                                                    # The circumference of the wheel is diameter times pi.
    degrees_to_turn = 360 * inches / (wheel_diameter * math.pi)
    while motorB.get_degrees_counted() < degrees_to_turn:
        print( "Degree: " + str(motorB.get_degrees_counted()) + "; Distance: " + str(wheel_diameter * math.pi * motorB.get_degrees_counted() / 360))
    motor_pair.stop()

drive_forward(10)                                   # Drive forward 10 inches
                                                    # Show the current degree and distance traveled
print( "Degree: " + str(motorB.get_degrees_counted()) + "; Distance: " + str(wheel_diameter * math.pi * motorB.get_degrees_counted() / 360))

Line Following Examples

Example 1: One Sensor to control steering

Example below shows a line following program that controls the steering parameter of the move function. Input to the steering parameter comes from the light sensor readings.

from spike import PrimeHub, Motor, MotorPair, ColorSensor
from spike.control import wait_for_seconds
import math
import sys

hub = PrimeHub()
light_sensor = ColorSensor('D')
light_sensor.light_up(30, 30, 30)                   # Dim the external light on the sensor to 30% power
wheel_diameter = 2.14                               # Diameter of the wheel in inches
motor_pair = MotorPair('B', 'C')                    # Pairs motors on ports B and C
motorB = Motor('B')                                 # Initialize a variable to keep track of motor B
motor_pair.start(0,-15)                             # Start the motors moving
motorB.set_degrees_counted(0)                       # Reset the encoder value
motor_pair.set_stop_action('coast')
def steer():
    steering = -1 * (light_sensor.get_reflected_light() - 60)
    motor_pair.move( 1, 'cm', steering, -15)
    message_log = "Degree: " + str( motorB.get_degrees_counted() )
    message_log += "; Distance: " + str( wheel_diameter * math.pi * motorB.get_degrees_counted() / 360 )
    message_log += "; LightSensor: " + str( light_sensor.get_reflected_light() )
    message_log += "; Steering: " + str( steering )
    print( message_log )

while True:
    steer()

Example 2: One Sensor to Control Steering

Example below shows a line following program that controls the steering parameter of the .start_at_power() method. Input to the steering parameter comes from the light sensor readings.

from spike import PrimeHub, Motor, MotorPair, ColorSensor
from spike.control import wait_for_seconds
import math
import sys

hub = PrimeHub()
default_speed = -25
light_sensor = ColorSensor('D')

wheel_diameter = 2.14                               # Diameter of the wheel in inches
motor_pair = MotorPair('B', 'C')                    # Pairs motors on ports B and C
motorB = Motor('B')                                 # Initialize a variable to keep track of motor B
motor_pair.start(0,-15)                             # Start the motors moving
motorB.set_degrees_counted(0)                       # Reset the encoder value
motor_pair.set_stop_action('coast')
print( 'About to start' )
print( '==============' )
i = 0
# In this example a constant is subtracted from the light sensor reading
# This constant value (75 in this example) represents the midpoint between the light and dark readings.
# Our robot was showing a value of 99 for the light readings and a value of about 50 for the dark readings.
# The constant (75) represents an approximation of the average of the readings.When subtracted from the
# light sensor value, the result will be a number that will vary between about +25 and -25.
# The valid values for steering are between -100 and +100 though we will not want to get that extreme.
# Multiply the amount of steering by a gain factor (-1.35 in this example).The negative sign for the gain
# is simply because we are going to follow one particular side of the line.If following the other side of
# the line, we would use a positive value for the gain.The numeric portion of the gain 1.35 was determined
# through trial and error.If the robot does not turn fast enough on the turns, then increase the value for the gain.
def steer(i):
    steering = -1.35 * (light_sensor.get_reflected_light() - 75)
    motor_pair.start_at_power(default_speed, int(steering))
    message_log = "Degree: " + str( motorB.get_degrees_counted() )
    message_log += "; Distance: " + str( wheel_diameter * math.pi * motorB.get_degrees_counted() / 360 )
    message_log += "; LightSensor: " + str( light_sensor.get_reflected_light() )
    message_log += "; Steering: " + str( steering )
    if (i % 4) == 0: print( message_log )
while True:
    steer(i)
    i += 1
A function is "defined" in the program as having a specific "type" (or return value). Most functions are created as the type: "void". A function declared as the type: "void" starts with the word "void" before the name of the function as in the following:

// I am declaring a function of type void below
void driveForward() {
}
Notice how the function definition includes function type (void), name, parentheses, and braces "{}" (both an open and a close brace). The commands that you write between the two braces are what will be executed when the function is "called".

Declaring a Function with Arguments

Arguments (or "Parameters" as they are sometimes called) can be passed to the function by declaring them between the parentheses in the function's definition. For example:

// Declare a function with a distance parameter
void driveForward(int distance) {
  forward(distance*30, degrees, robot.powerLevel); 
}
In this example, the driveForward() function has an added parameter called: "distance" that was defined as a type: "int". In the example above, my "driveForward(distance)" function is "calling" an internal RobotC function called: "forward()" which has three parameters: amount, type, and power.

In my program, I could have just used the internal RobotC function called forward(). However, that function requires 3 parameters which means that I have to always include the amount, type, and power level parameters whenever I want to drive forward. My user defined function is a "short cut" allowing me to call my function with one parameter which will then automatically fill in the other two parameters when calling the internal RobotC function.

Defined BEFORE it can be Used

One note of caution. You have to define the function before you can use it. This seems to make sense. But what this means is that the tops of your programs may contain many function definitions before you get to the actual sequence of your program that makes the robot do its mission.

Note: Functions must be defined before the "main task".

The "task main() { }"

One very important function block in all RobotC programs is the "task main" (see below).

// This is the "main" task
task main() {
}
Program execution starts at the "main" task. The "main()" function is defined as a type "task". The "task" type is a special keyword and should be used only for the main() function. In order for your program to work, it needs to have one line (towards the bottom) that says: "task main() {"

It is possible to have more than one function defined with the type "task". Doing so would create a multi-threaded program which has some unique capabilities in responsiveness of the robot.

Exercise

Exercise: Write a small program that creates a function (before the main task). Call that function from within the main task.