Conversion Functions
This section includes helper functions that are used throughout the robot code to convert between distance (in centimeters) and motor rotation (in degrees), as well as to check the current battery level of the EV3 brick.
check_battery()
This function displays the current battery level on the LCD screen of the EV3 brick.
The value returned by EV3.BatteryLevel is the
battery voltage in millivolts (e.g., 7900 = 7.9V).
It's useful for debugging or preventing the robot from running with low power.
Sub check_battery
LCD.Clear() ' Clears any previous text from the screen
LCD.Write(0, 70, EV3.BatteryLevel) ' Writes the battery level at X=0, Y=70
LCD.Update() ' Refreshes the LCD screen to show the value
EndSub
cm2degree(cm, degrees)
This function converts a physical distance in centimeters into the number of
degrees the motor must rotate to cover that distance.
It's required because motors only work with rotation values, not linear distances.
The formula is:
degrees = (cm × 360) / (π × wheel_diameter)
Here, @wheel_diameter is a global variable set to match your robot's wheels.
Function cm2degree (in number cm, out number degrees)
degrees = cm * 360 / ( Math.Pi * @wheel_diameter )
EndFunction
degree2cm(degrees, cm)
This function does the reverse of cm2degree. It converts motor rotation in
degrees
back into a linear distance in centimeters.
The formula is:
cm = degrees / (360 / (π × wheel_diameter))
Function degree2cm (in number degrees, out number cm)
cm = degrees / ( 360 / ( Math.Pi * @wheel_diameter ) )
EndFunction
Acceleration & Deceleration
When a robot starts or stops movement, it can jerk or skid if motors instantly jump to a high speed or stop abruptly. To make movement smoother and prevent mechanical stress, we use acceleration and deceleration curves that gradually increase or decrease speed.
How Acceleration Works
The idea is to slowly raise motor speed from a minimum value (e.g., @start_speed) to the desired maximum speed (max_speed)
over a certain distance defined by @AccelerateEncoder. This creates a ramp-up effect.
Formula:
V = (CurrentEncoder / @AccelerateEncoder) × (max_speed - @start_speed) + @start_speed
This makes the speed increase proportionally as the robot travels further.
' Acceleration Curve
If acceleration = "on" Then
V = ( CurrentEncoder / @AccelerateEncoder ) * ( max_speed - @start_speed * sens ) + @start_speed * sens
V = Math.Abs(V) * sens
If Math.Abs(V) > Math.Abs(max_speed) Then
V = max_speed
EndIf
ElseIf acceleration = "off" Then
V = max_speed
EndIf
How Deceleration Works
Deceleration is the opposite: gradually reducing speed as the robot gets closer to the end of its movement. It improves stopping accuracy and prevents the robot from overshooting.
It works based on the distance remaining to the goal, using @DecelerateEncoder as the range.
Formula:
V = ((encoder - CurrentEncoder) / @DecelerateEncoder) × (max_speed - @start_speed) + @start_speed
' Deceleration Curve
If deceleration = "on" Then
If encoder - CurrentEncoder < @DecelerateEncoder Then
V = ((encoder - CurrentEncoder) / @DecelerateEncoder) * (max_speed - @start_speed * sens) + @start_speed * sens
V = Math.Abs(V) * sens
If Math.Abs(V) < Math.Abs(@start_speed * sens) Then
V = @start_speed * sens
EndIf
EndIf
EndIf
When to Use
- Use
acceleration = "on"when you want smoother starts, especially in longer movement sequences. - Use
deceleration = "on"when the robot needs to stop precisely (e.g., before turning or grabbing an object). - You can combine both acceleration and deceleration for full curve control.
Line Follower - Dual Sensor
This section explains how to follow a black line using two sensors and a PD controller.
It includes acceleration, deceleration, and end brake logic to ensure smooth, accurate, and stable movement.
Why use Acceleration & Deceleration?
Motors are not perfect — if you instantly set a high speed, the robot may jerk, spin, or lose the line. Acceleration gradually increases speed at the beginning, making the robot stable and reducing slippage.
Deceleration gradually reduces the speed near the end of movement. Without it, your robot may overshoot the stop point or shake during a turn transition. It helps with precision.
Why use End Brake?
The end brake logic stops the motors firmly once the target distance is reached.
It is especially useful when your robot has to stop before an action — like turning, reading a color, or picking up an object.
If end_brake = "on", it uses Motor.Stop() at the end of the movement.
What is PD Control?
The robot reads the difference between the two sensors to calculate an error (how far from center it is).
Then it applies a Proportional and Derivative correction:
P = kp × error controls how hard the robot should react.
D = kd × (error - previous_error) slows down rapid changes.
Function LineFollower_2S_Encoder (in number max_speed, in number encoder_cm, in string acceleration, in string deceleration, in string end_brake)
Sensor.SetMode(@left_sensor,0)
Sensor.SetMode(@right_sensor,0)
Motor.ResetCount("BC")
error_old = 0
exit_condition = 1
cm2degree(encoder_cm, encoder)
While exit_condition = 1
s1 = Sensor.ReadPercent(@left_sensor)
s2 = Sensor.ReadPercent(@right_sensor)
CurrentEncoder = (Math.Abs(Motor.GetCount(@left_motor)) + Math.Abs(Motor.GetCount(@right_motor))) / 2
If max_speed < 0 Then
sens = -1
Else
sens = 1
EndIf
If acceleration = "on" Then
V = (CurrentEncoder / @AccelerateEncoder) * (max_speed - @start_speed * sens) + @start_speed * sens
V = Math.Abs(V) * sens
If Math.Abs(V) > Math.Abs(max_speed) Then
V = max_speed
EndIf
ElseIf acceleration = "off" Then
V = max_speed
EndIf
If deceleration = "on" Then
If encoder - CurrentEncoder < @DecelerateEncoder Then
V = ((encoder - CurrentEncoder) / @DecelerateEncoder) * (max_speed - @start_speed * sens) + @start_speed * sens
V = Math.Abs(V) * sens
If Math.Abs(V) < Math.Abs(@start_speed * sens) Then
V = @start_speed * sens
EndIf
EndIf
EndIf
If @debug = "on" Then
LCD.Write(10,30, @start_speed*sens)
LCD.Write(50,30, V)
LCD.Update()
EndIf
error = s1 - s2
P = @kp_lf * error
D = @kd_lf * (error - error_old)
If @debug = "on" Then
LCD.Write(10,50, V)
LCD.Write(50,50, P + D)
LCD.Write(100,50, V + P + D)
LCD.Update()
EndIf
If @motor_type = "medium" Then
Motor_Left = -1 * (V + (P + D))
Else
Motor_Left = V + (P + D)
EndIf
Motor_Right = V - (P + D)
error_old = error
Motor.StartPower(@left_motor, Motor_Left)
Motor.StartPower(@right_motor, Motor_Right)
If CurrentEncoder > encoder Then
exit_condition = 0
EndIf
EndWhile
If end_brake = "on" Then
Motor.Stop("BC", "True")
EndIf
EndFunction
Line Following with a Single Sensor
When only one sensor is available, we can still follow a line using a PD controller and a reference value for grey. The difference from a dual-sensor setup is that we compare the current sensor reading to a fixed grey value instead of another sensor. This is especially useful when you want a smaller or simpler robot that uses fewer ports.
LineFollower_1S_Encoder()
This function allows the robot to follow a line using only one sensor until it reaches a specific encoder value. The robot calculates the error between the current sensor reading and the reference grey value. Based on the selected side ("left" or "right"), the controller applies power corrections using PD logic.
Function LineFollower_1S_Encoder (in number port, in string side, in number kp, in number kd, in number max_speed, in number encoder_cm, in string acceleration, in string deceleration, in string end_brake)
Sensor.SetMode(port, 0) ' Mode 0, light reflection
Motor.ResetCount("BC")
error_old = 0
exit_condition = 1
cm2degree(encoder_cm, encoder)
While exit_condition = 1
s1 = Sensor.ReadPercent(port)
s2 = @grey
CurrentEncoder = ( Math.Abs(Motor.GetCount(@left_motor)) + Math.Abs(Motor.GetCount(@right_motor)) ) / 2
If acceleration = "on" Then
V = ( CurrentEncoder / @AccelerateEncoder ) * ( max_speed - @start_speed ) + @start_speed
If V > max_speed Then V = max_speed
Else
V = max_speed
EndIf
If deceleration = "on" Then
If encoder - CurrentEncoder < @DecelerateEncoder Then
V = ( (encoder - CurrentEncoder) / @DecelerateEncoder ) * ( max_speed - @start_speed ) + @start_speed
If V < @start_speed Then V = @start_speed
EndIf
EndIf
If side = "left" Then
error = s1 - s2
Else
error = s2 - s1
EndIf
P = kp * error
D = kd * (error - error_old)
error_old = error
Motor_Left = V + (P + D)
Motor_Right = V - (P + D)
Motor.StartPower(@left_motor, Motor_Left)
Motor.StartPower(@right_motor, Motor_Right)
If CurrentEncoder > encoder Then exit_condition = 0
EndWhile
If end_brake = "on" Then
Motor.Stop("BC", "True")
EndIf
EndFunction
Detecting Intersections
To follow a line until an intersection (instead of an encoder value), we use a second color sensor or the one we are doing the line follower on. This sensor is continuously monitored, and when its value drops below a black threshold (usually around 10–20), the robot recognizes it has reached an intersection.
The logic is similar to LineFollower_1S_Encoder, but the exit condition changes:
If stop_port_reading < @black_value Then
exit_condition = 0
EndIf
This check allows the robot to stop exactly when a dark line or intersection is detected by the stop sensor, improving timing and precision.
Line Following with Two Sensors - Intersection
This page focuses on performing a two-sensor line following routine until an intersection is reached. This is essential for navigating robotics courses with branching paths, stops, or checkpoints.
How It Works
Using a standard PD controller, the robot constantly corrects its course based on two sensors placed on either side of the line. When one of the sensors detects a black value (an intersection), the robot knows it's time to stop or align for rotation.
Intersection Exit Condition
The condition If s1 < @black_value + 2 Or s2 < @black_value + 2 Then tells the robot to exit the loop as soon as either sensor sees black, meaning the robot has reached a junction or crossroad.
Why Alignment and End Brake?
-
Alignment: After reaching an intersection, aligning the robot with the center of rotation ensures more accurate turns.
End Brake: If enabled, it stops the motors with a brake for better positioning and consistency.
Function LF_2S_Intersection (in number max_speed, in string acceleration, in string move_until_center_of_rotation, in string end_brake)
Sensor.SetMode(@left_sensor, 0) ' Sensor Mode 0, for reflected light
Sensor.SetMode(@right_sensor, 0) ' Sensor Mode 0, for reflected light
Motor.ResetCount("BC")
error_old = 0
exit_condition = 1
While exit_condition = 1
s1 = Sensor.ReadPercent(@left_sensor)
s2 = Sensor.ReadPercent(@right_sensor)
CurrentEncoder = ( Math.Abs(Motor.GetCount(@left_motor)) + Math.Abs(Motor.GetCount(@right_motor)) ) / 2
If acceleration = "on" Then
V = ( CurrentEncoder / @AccelerateEncoder ) * ( max_speed - @start_speed ) + @start_speed
V = Math.Abs( V )
If V > max_speed Then V = max_speed
ElseIf acceleration = "off" Then
V = max_speed
EndIf
error = s1 - s2
P = @kp_lf * error
D = @kd_lf * (error - error_old)
If @motor_type = "medium" Then
Motor_Left = -1 * ( V + (P + D) ' for medium motors one motor will always be negative to move forward
Else
Motor_Left = V + (P + D)
EndIf
Motor_Right = V - (P + D)
error_old = error
Motor.StartPower(@left_motor, Motor_Left)
Motor.StartPower(@right_motor, Motor_Right)
If s1 < @black_value + 2 Or s2 < @black_value + 2 Then
exit_condition = 0
EndIf
EndWhile
If move_until_center_of_rotation = "on" Then
MoveSync_Encoder(@wheel_to_sensor_distance, max_speed, "off", "off", "off")
EndIf
If end_brake = "on" Then
Motor.Stop("BC", "True")
EndIf
EndFunction
Move with Encoder
This function is used when you want to move the robot a specific distance. Because EV3 motors measure rotation in degrees,
we convert centimeters to degrees using the cm2degree() helper function.
Move_Sync_Encoder()
Synchronizes both motors to move in a straight line using encoder feedback. Includes optional acceleration and deceleration profiles. It also uses a PD (Proportional-Derivative) controller to keep both motors aligned.
Function Move_Sync_Encoder (in number encoder_cm, in number max_speed, in string acceleration, in string deceleration, in string end_brake)
Motor.ResetCount(@left_motor)
Motor.ResetCount(@right_motor)
cm2degree(encoder_cm, encoder)
error_old = 0
exit_condition = 1
While exit_condition = 1
left_encoder = Motor.GetCount(@left_motor)
right_encoder = Motor.GetCount(@right_motor)
CurrentEncoder = (Math.Abs(left_encoder) + Math.Abs(right_encoder)) / 2
If acceleration = "on" Then
V = (CurrentEncoder / @AccelerateEncoder) * (max_speed - @start_speed) + @start_speed
If V > max_speed Then
V = max_speed
EndIf
Else
V = max_speed
EndIf
If deceleration = "on" And encoder - CurrentEncoder < @DecelerateEncoder Then
V = ((encoder - CurrentEncoder) / @DecelerateEncoder) * (max_speed - @start_speed) + @start_speed
If V < @start_speed Then
V = @start_speed
EndIf
EndIf
error = right_encoder - left_encoder
P = @kp_move_sync * error
D = @kd_move_sync * (error - error_old)
Motor_Left = V + P + D
Motor_Right = V - P - D
Motor.StartPower(@left_motor, Motor_Left)
Motor.StartPower(@right_motor, Motor_Right)
error_old = error
If Math.Abs(CurrentEncoder) > encoder Then
exit_condition = 0
EndIf
EndWhile
If end_brake = "on" Then
Motor.Stop("BC", "True")
EndIf
EndFunction
Move Until Color
This movement ends when a specific color is detected by either sensor. Common use cases include stopping at a green zone or aligning to black lines.
MoveSync_To_Color()
The robot moves forward while continuously checking for a color match. It supports RGB and HSV detection depending on the selected color. Use this when you want to stop on black, white, green, blue, or brown zones.
Function MoveSync_To_Color(in number max_speed, in string acceleration, in string end_brake, in string colour)
Sensor.SetMode(1, 0)
Sensor.SetMode(2, 0)
Motor.ResetCount("BC")
error_old = 0
exit_condition = 1
While exit_condition = 1
left_encoder = Motor.GetCount(@left_motor)
right_encoder = Motor.GetCount(@right_motor)
CurrentEncoder = (Math.Abs(left_encoder) + Math.Abs(right_encoder)) / 2
If acceleration = "on" Then
V = (CurrentEncoder / @AccelerateEncoder) * (max_speed - @start_speed) + @start_speed
If V > max_speed Then
V = max_speed
EndIf
Else
V = max_speed
EndIf
error = right_encoder - left_encoder
P = @kp_move_sync * error
D = @kd_move_sync * (error - error_old)
Motor_Left = V + P + D
Motor_Right = V - P - D
Motor.StartPower(@left_motor, Motor_Left)
Motor.StartPower(@right_motor, Motor_Right)
error_old = error
HSV_Read(1, val)
If val = 3 Then
exit_condition = 0
EndIf
HSV_Read(2, val)
If val = 3 Then
exit_condition = 0
EndIf
EndWhile
If end_brake = "on" Then
Motor.Stop("BC", "True")
EndIf
EndFunction
Move Along Wall
This move sync variation keeps the robot aligned to a wall using a fixed speed difference between the motors.
MoveSync_Encoder_On_Wall()
The motors are adjusted to push slightly against the wall on one side (left or right). Great for guiding along borders or guiding rails.
Function MoveSync_Encoder_On_Wall(in number encoder_cm, in number max_speed, in string side, in string acceleration, in string deceleration, in string end_brake)
Motor.ResetCount(@left_motor)
Motor.ResetCount(@right_motor)
cm2degree(encoder_cm, encoder)
exit_condition = 1
While exit_condition = 1
left_encoder = Motor.GetCount(@left_motor)
right_encoder = Motor.GetCount(@right_motor)
CurrentEncoder = (Math.Abs(left_encoder) + Math.Abs(right_encoder)) / 2
If acceleration = "on" Then
V = (CurrentEncoder / @AccelerateEncoder) * (max_speed - @start_speed) + @start_speed
If V > max_speed Then
V = max_speed
EndIf
Else
V = max_speed
EndIf
If deceleration = "on" And encoder - CurrentEncoder < @DecelerateEncoder Then
V = ((encoder - CurrentEncoder) / @DecelerateEncoder) * (max_speed - @start_speed) + @start_speed
If V < @start_speed Then
V = @start_speed
EndIf
EndIf
Motor_Left = V
Motor_Right = V
If side = "left" Then
Motor_Right += @speed_dif_wall
Else
Motor_Left += @speed_dif_wall
EndIf
Motor.StartPower(@left_motor, Motor_Left)
Motor.StartPower(@right_motor, Motor_Right)
If Math.Abs(CurrentEncoder) > encoder Then
exit_condition = 0
EndIf
EndWhile
If end_brake = "on" Then
Motor.Stop("BC", "True")
EndIf
EndFunction
Wall-Guided Move Until Color
Combines wall-following behavior with color detection. This allows the robot to hug a wall and stop only when a specific color is reached.
MoveSync_OnWall_To_Color()
Adjusts motor speed just like the wall-following function, and checks color at the same time. Works with brown, black, green, and white surfaces.
Function MoveSync_OnWall_To_Color(in number max_speed, in string side, in string acceleration, in string end_brake, in string colour)
Motor.ResetCount(@left_motor)
Motor.ResetCount(@right_motor)
exit_condition = 1
While exit_condition = 1
left_encoder = Motor.GetCount(@left_motor)
right_encoder = Motor.GetCount(@right_motor)
CurrentEncoder = (Math.Abs(left_encoder) + Math.Abs(right_encoder)) / 2
If acceleration = "on" Then
V = (CurrentEncoder / @AccelerateEncoder) * (max_speed - @start_speed) + @start_speed
If V > max_speed Then
V = max_speed
EndIf
Else
V = max_speed
EndIf
Motor_Left = V
Motor_Right = V
If side = "left" Then
Motor_Right += @speed_dif_wall
Else
Motor_Left += @speed_dif_wall
EndIf
Motor.StartPower(@left_motor, Motor_Left)
Motor.StartPower(@right_motor, Motor_Right)
HSV_Read(@left_sensor, val)
If val = 3 Then e
xit_condition = 0
EndIf
HSV_Read(@right_sensor, val)
If val = 3 Then
exit_condition = 0
EndIf
EndWhile
If end_brake = "on" Then
Motor.Stop("BC", "True")
EndIf
EndFunction
Turning & Rotation
The following functions handle all types of turning: arc-based movement, in-place spinning, and S-shaped shifting using both large and medium EV3 motors. Each movement is calculated based on the geometry of the robot and uses trigonometric formulas to ensure precision.
Arc_Move()
This function allows the robot to move along a circular path. It calculates two arc lengths: one for the inner wheel (L1) and one for the outer wheel (L2), based on the given radius R and rotation angle degrees. The ratio P = L1 / L2 is used to adjust motor speeds for smooth arc movement.
The conversion from centimeters to motor degrees is handled by cm2degree(), and the arc lengths are derived using:
L = 2πR × (angle / 360). An additional correction (+0.2) is applied to account for mechanical offsets in wheel distance.
Function Arc_Move(in number degrees, in number R, in string direction, in number speed)
Motor.ResetCount("BC")
cm2degree(1, dist)
R1 = R * dist
R2 = R1 + (@wheel_distance + 0.2) * dist
L1 = 2 * Math.Pi * R1 * degrees / 360
L2 = 2 * Math.Pi * R2 * degrees / 360
P = L1 / L2
If @motor_type = "large" Then
If direction = "right" Then
Motor.MoveSync("BC", speed, speed * P, L2, "true")
Else
Motor.MoveSync("BC", speed * P, speed, L2, "true")
EndIf
Else
If direction = "right" Then
Motor.MoveSync("BC", -1 * speed, speed * P, L2, "true")
Else
Motor.MoveSync("BC", speed * P, -1 * speed, L2, "true")
EndIf
EndIf
EndFunction
Arc_Move_Encoder()
This version of arc movement uses encoder feedback instead of predefined arc length. It accepts motor speeds for the left and right wheels independently and keeps running until the average encoder count reaches the target distance.
For medium motors, where MoveSync is not available, a PD controller is used to adjust motor speeds based on encoder differences. The error is calculated as:
error = left_encoder × sign + right_encoder × ratio, where sign ensures proper correction depending on motor direction, and ratio keeps the curve shape.
Function Arc_Move_Encoder(in number encoder_cm, in number left_speed, in number right_speed, in string end_brake)
Motor.ResetCount("B")
Motor.ResetCount("C")
error_old = 0
exit_condition = 1
cm2degree(encoder_cm, encoder)
If @motor_type = "large" Then
Motor.MoveSync(@stop_string, left_speed, right_speed, encoder, "True")
Else
While exit_condition = 1
left_encoder = Motor.GetCount(@left_motor)
right_encoder = Motor.GetCount(@right_motor)
CurrentEncoder = (Math.Abs(left_encoder) + Math.Abs(right_encoder)) / 2
sign = Math.Abs(left_speed * right_speed - 1) - Math.Abs(left_speed * right_speed)
ratio = left_speed / right_speed
error = left_encoder * sign + right_encoder * ratio
error_old = error
P = @kp_move_sync_vir * error
D = @kd_move_sync_vir * (error - error_old)
Motor_Left = left_speed - (P + D) * sign
Motor_Right = right_speed - (P + D)
Motor.StartPower(@left_motor, Motor_Left)
Motor.StartPower(@right_motor, Motor_Right)
If CurrentEncoder >= encoder Then
exit_condition = 0
EndIf
EndWhile
EndIf
If @debug = "off" Then
LCD.Clear()
LCD.Write(1, 10, Motor.GetCount(@left_motor))
LCD.Write(1, 20, Motor.GetCount(@right_motor))
LCD.Update()
EndIf
If end_brake = "on" Then
Motor.Stop(@stop_string, "True")
EndIf
EndFunction
Turn_In_Place()
Rotates the robot in place by running the left and right motors in opposite directions. The amount of rotation in degrees is first converted to linear distance using:
distance = angle × wheel_distance × π / 360. This value is then passed to Arc_Move_Encoder() to handle exact movement using encoder feedback.
Function Turn_In_Place(in number degrees, in string direction, in number speed, in string end_brake)
move_tank_cm = degrees * @wheel_distance * Math.Pi / 360
If direction = "left" Then
If @motor_type = "large" Then
left_speed = -1 * speed
right_speed = speed
Else
left_speed = speed
right_speed = speed
EndIf
Else
If @motor_type = "large" Then
left_speed = speed
right_speed = -1 * speed
Else
left_speed = -1 * speed
right_speed = -1 * speed
EndIf
EndIf
Arc_Move_Encoder(move_tank_cm, left_speed, right_speed, end_brake)
EndFunction
S_Move()
This function makes the robot shift to the side in an S-shaped motion. The angle needed to perform each curve is calculated using the inverse cosine formula:
degrees = arccos(1 - d / D) × (2D / wheel_diameter) × (180 / π), where d is the lateral shift and D is the distance between wheels.
The robot performs two consecutive arcs in opposite directions, resulting in a smooth lateral displacement. Useful for centering or aligning without changing orientation.
Function S_Move (in number distance, in string direction, in string end_brake)
degrees = Math.ArcCos(1 - distance / @wheel_distance) * 2 * @wheel_distance / @wheel_diameter * 180 / Math.Pi
If @motor_type = "large" Then
If direction = "right" Then
Motor.MoveSync("BC", @turn_speed, 0, degrees, "True")
Motor.MoveSync("BC", 0, @turn_speed, degrees, "True")
Else
Motor.MoveSync("BC", 0, @turn_speed, degrees, "True")
Motor.MoveSync("BC", @turn_speed, 0, degrees, "True")
EndIf
Else
If direction = "right" Then
Motor.MoveSync("BC", -1 * @turn_speed, 0, degrees, "True")
Motor.MoveSync("BC", 0, @turn_speed, degrees, "True")
Else
Motor.MoveSync("BC", 0, @turn_speed, degrees, "True")
Motor.MoveSync("BC", -1 * @turn_speed, 0, degrees, "True")
EndIf
EndIf
If end_brake = "on" Then
Motor.Stop("BC", "True")
EndIf
EndFunction
Alignment Functions
This function ensures that the robot is perfectly aligned to a wall or fixed object. It is especially useful for resetting orientation before starting a precise movement or routine. The technique works by driving both motors forward or backward and waiting for one motor to slow down due to wall contact, indicating alignment.
The function continuously checks the current speed of each motor. If one of them significantly drops (i.e., when it hits the wall), or a maximum time limit is reached, the motors stop.
For medium motors, the direction is handled differently because one motor is mounted in reverse. The direction check ensures compatibility with both large and medium motor configurations.
Function alignment(in string direction, in number speed)
exit_condition = 0
If @motor_type = "large" Then
If direction = "forward" Then
Motor.Start("B", speed)
Motor.Start("C", speed)
Else
Motor.Start("B", speed)
Motor.Start("C", speed)
EndIf
Else
If direction = "forward" Then
Motor.Start("B", speed)
Motor.Start("C", -1 * speed)
Else
Motor.Start("B", -1 * speed)
Motor.Start("C", speed)
EndIf
EndIf
Program.Delay(400) ' Initial delay to start the movement
Time.Reset1()
While exit_condition = 0
If Time.Get1() > @alignment_time Then
exit_condition = 1
EndIf
EndWhile
Motor.Stop("BC", "True")
EndFunction
Sensor Reading: Color & Distance Sensors
EV3 sensors can operate in different modes, depending on what kind of data you want to gather. Below we explain the available modes and how to use them effectively in EV3 Basic for Color Sensors and Distance Sensors (Ultrasonic and Infrared).
Color Sensor Modes
-
Mode 0 – Reflected Light Intensity: returns a percentage (0–100) of reflected light. Use
Sensor.ReadPercent(port).
Mode 1 – Ambient Light: returns a percentage of surrounding light. Use Sensor.ReadPercent(port).
Mode 2 – Color Detection: returns a code (0–7) for standard LEGO colors. Use Sensor.ReadRawValue(port, 0).
Mode 4 – RGB Raw Values: returns an array of 3 values (red, green, blue). Use Sensor.ReadRaw(port, 3).
' Mode 0 – Reflected Light Intensity
Sensor.SetMode(3, 0)
value = Sensor.ReadPercent(3)
LCD.Text(1, 10, 10, 2, "Reflected: " + value)
' Mode 1 – Ambient Light
Sensor.SetMode(3, 1)
value = Sensor.ReadPercent(3)
LCD.Text(1, 10, 10, 2, "Ambient: " + value)
' Mode 2 – Color Detection
Sensor.SetMode(3, 2)
colorCode = Sensor.ReadRawValue(3, 0)
Colors[0] = "UNKNOWN"
Colors[1] = "BLACK"
Colors[2] = "BLUE"
Colors[3] = "GREEN"
Colors[4] = "YELLOW"
Colors[5] = "RED"
Colors[6] = "WHITE"
Colors[7] = "BROWN"
LCD.Text(1, 33, 40, 2, "Color: " + Colors[colorCode])
' Mode 4 – RGB Values
Sensor.SetMode(3, 4)
RGB = Sensor.ReadRaw(3, 3)
red = RGB[0]
green = RGB[1]
blue = RGB[2]
LCD.Text(1, 10, 30, 2, "R: " + red)
LCD.Text(1, 10, 50, 2, "G: " + green)
LCD.Text(1, 10, 70, 2, "B: " + blue)
Ultrasonic Sensor Modes
-
Mode 0 – Distance in mm: use
Sensor.ReadRawValue(port, 0).
Mode 1 – Distance in tenths of an inch: use Sensor.ReadRawValue(port, 0).
' Ultrasonic Distance in cm (mode 0)
Sensor.SetMode(4, 0)
distance_mm = Sensor.ReadRawValue(4, 0)
LCD.Text(1, 45, 55, 2, distance_mm / 10 + " cm")
' Ultrasonic Distance in inches (mode 1)
Sensor.SetMode(4, 1)
distance_tenthinches = Sensor.ReadRawValue(4, 0)
LCD.Text(1, 45, 55, 2, distance_tenthinches / 10 + " in")
Infrared Sensor Modes
-
Mode 0 – Proximity: returns distance to an obstacle in cm. Use
Sensor.ReadPercent(port).
Mode 1 – Beacon (Direction + Distance): returns array [direction, distance]. Use Sensor.ReadRaw(port, 2).
Mode 2 – Remote Buttons: returns button codes using Sensor.ReadRawValue(port, channel).
' IR Sensor – Proximity
Sensor.SetMode(4, 0)
distance = Sensor.ReadPercent(4)
LCD.Text(1, 10, 10, 2, distance + " cm")
' IR Sensor – Beacon (Direction + Distance)
Sensor.SetMode(4, 1)
data = Sensor.ReadRaw(4, 2)
direction = data[0]
distance = data[1]
LCD.Text(1, 10, 20, 2, "Dir: " + direction)
LCD.Text(1, 10, 40, 2, "Dist: " + distance)
' IR Sensor – Remote Control Button
Sensor.SetMode(4, 2)
channel = 0 ' choose channel 0 to 3
buttonCode = Sensor.ReadRawValue(4, channel)
LCD.Text(1, 10, 60, 2, "Button: " + buttonCode)
Always remember to Sensor.SetMode() before using any sensor. The wrong mode will give incorrect results or crash your code.
HSV & RGB Detection
Color sensors on the EV3 can detect light intensity in several modes. Two of the most powerful modes are RGB (Red, Green, Blue) and HSV (Hue, Saturation, Value). RGB measures the amount of red, green, and blue light reflected by a surface, while HSV transforms these values to make it easier to classify colors based on how we perceive them visually.
What is RGB?
RGB stands for Red, Green, Blue. The sensor provides three values representing how much of each color is reflected by an object. For example, white surfaces reflect all three colors highly, while black absorbs all. RGB is helpful for detecting subtle differences in color, but may vary based on lighting conditions.
What is HSV?
HSV stands for Hue, Saturation, and Value. It's a way of interpreting RGB data in a more intuitive way:
-
Hue: the actual color (e.g., red, green, blue), measured in degrees on a 0–360° scale.
Saturation: how strong or pure the color is (0 = gray, 1 = fully saturated color).
Value: brightness of the color (0 = black, 1 = full brightness).
Read_RGB(port)
This function continuously reads RGB values from a color sensor and displays both live and maximum values for red, green, and blue. Useful for color calibration and debugging.
Function Read_RGB (in number port)
' Initialize values
red = 0
green = 0
blue = 0
MaxRed = 0
MaxGreen = 0
MaxBlue = 0
' Set color sensor mode to RGB (mode 4)
Sensor.SetMode(port, 4)
LCD.Clear()
' Keep reading until center button is pressed
While Buttons.GetClicks() <> "E"
' Read RGB values from the chosen port
If port = 1 Then
Sensor1.Raw3(red, green, blue)
If port = 2 Then
Sensor2.Raw3(red, green, blue)
If port = 3 Then
Sensor3.Raw3(red, green, blue)
If port = 4 Then
Sensor4.Raw3(red, green, blue)
' Save maximum values
If red > MaxRed Then
MaxRed = red
If green > MaxGreen Then
MaxGreen = green
If blue > MaxBlue Then
MaxBlue = blue
' Display current and max RGB values
LCD.Clear()
LCD.Write(1,1, "R: ") : LCD.Write(20,1, red)
LCD.Write(1,15, "G: ") : LCD.Write(20,15, green)
LCD.Write(1,30, "B: ") : LCD.Write(20,30, blue)
LCD.Write(1,45, "maxR: ") : LCD.Write(40,45, MaxRed)
LCD.Write(1,60, "maxG: ") : LCD.Write(40,60, MaxGreen)
LCD.Write(1,75, "maxB: ") : LCD.Write(40,75, MaxBlue)
LCD.Update()
Wait(0.3)
EndWhile
' Wait so values remain visible
Wait(5)
EndFunction
HSV_Read(port, out color)
This function reads RGB values, normalizes them, and converts to HSV. Based on hue, saturation, and value, it determines a simplified color code (e.g., red, green, blue, black, white).
Function HSV_Read (in number port, out number color)
Sensor.SetMode(port, 4)
red = 0
green = 0
blue = 0
' Read RGB values depending on port
If port = 1 Then
Sensor1.Raw3(red, green, blue)
If port = 2 Then
Sensor2.Raw3(red, green, blue)
If port = 3
Then Sensor3.Raw3(red, green, blue)
If port = 4 Then
Sensor4.Raw3(red, green, blue)
' Normalize values to 0-255 range
red = red / @max_R * 255
green = green / @max_G * 255
blue = blue / @max_B * 255
' Find min and max RGB components
max = Math.Max(Math.Max(red, green), blue)
min = Math.Min(Math.Min(red, green), blue)
' Hue calculation
If max = min Then
hue = 0
If max = red Then
If green >= blue Then
hue = 60 * (green - blue) / (max - min)
Else
hue = 60 * (green - blue) / (max - min) + 360
EndIf
If max = green Then
hue = 60 * (blue - red) / (max - min) + 120
If max = blue Then
hue = 60 * (red - green) / (max - min) + 240
' Saturation and Value
sat = If(max = 0, 0, 1 - min / max)
val = max / 255
' Determine color based on HSV thresholds
If sat >= 0.55 And val >= 0.09 Then
If hue <= 7 Then
color = 5 ' red
ElseIf hue <= 62 Then
color = 4 ' yellow
ElseIf hue <= 220 Then
color = 3 ' green
ElseIf hue <= 270 Then
color = 2 ' blue
Else
color = 5 ' red
ElseIf val <= 0.25 And val >= 0.05 Then
color = 1 ' black
Else
If val > 0.25 Then
color = 6 ' white
Else
color = 0 ' none
EndIf
' Debug display
If @debug = "on" Then
LCD.Clear()
LCD.Write(20, 20, "r=" + red)
LCD.Write(20, 40, "g=" + green)
LCD.Write(20, 60, "b=" + blue)
LCD.Write(20, 80, "hue=" + hue)
LCD.Write(20, 100, "col=" + color)
LCD.Update()
EndIf
EndFunction
Wait & Button Functions
These functions are used for implementing delays and user interaction via button presses on the EV3 brick. They are essential for creating pauses in execution and for waiting until the user gives a signal to proceed, such as pressing the center button.
Wait()
The Wait() function halts the program for a specified number of seconds. It uses the EV3 timer system by resetting Timer5 and waiting in a loop until the desired time has passed. The time is measured in milliseconds, so the input seconds are multiplied by 1000. We are not using Program.delay() because this function repeats last code line for that specified time.
Function Wait (in number time_in_sec)
Time.Reset5()
While Time.Get5() < time_in_sec * 1000
EndWhile
EndFunction
wait_until_press()
The wait_until_press() subroutine pauses execution until the center button on the EV3 brick is pressed. It continuously checks the button state using Buttons.GetClicks() and exits the loop when the button "E" (Enter) is detected.
This is commonly used at the start of programs to ensure the user is ready before the robot begins moving or for example to stop the robot in middle of the program to measure something or to just check its position.
Sub wait_until_press
While Buttons.GetClicks() <> "E" 'center button
EndWhile
EndSub
Threading & Background Processes
This function is an example of a continuous background task that runs parallel to the main program. In EV3-G or CLEV3R environments, such background subroutines are useful for keeping time, managing manipulators, or running diagnostics while the main algorithm continues. Especially to always keep arms/claws and lifts in tension so they won't lose position, or simple to be able to grab objects.
The subroutine shown below uses Time.Reset9() to track how long the program has been running, triggering a sound alert after 2 minutes using Speaker.Tone(). It also implements a PD controller for manipulating the robot arm's claw and lift, using motors A and D. These are controlled based on error correction between the current and target positions deltaA and deltaD.
' Starting the Thread:
Thread.Run = Thread_Sub
' Main Function
Sub Thread_Sub
Time.Reset9() ' reset timer for 2-minute countdown
@stop_sound = 0
erroldA = 0
erroldD = 0
Motor.ResetCount("AD")
While 1 > 0 ' Infinite loop
' Arm Manipulation Logic
errD = deltaD - Motor.GetCount("D")
errA = deltaA - Motor.GetCount("A")
vitD = kpLift * errD + kdLift * (errD - erroldD)
erroldD = errD
vitA = kpClaw * errA + kdClaw * (errA - erroldA)
erroldA = errA
Motor.StartPower("D", vitD)
Motor.StartPower("A", vitA)
EndWhile
EndSub
This type of threaded subroutine ensures your robot can perform real-time tasks like adjusting manipulators or monitoring sensors, even while another main task is executing simultaneously.
How to Use the Thread
This thread is designed to work with a lift and claw system controlled by delta values. To use it properly:
-
Start position of the lift and claw must will be at
0.
Call System_Init before anything else to set initial delta values:
Sub System_Init
@DeltaA = 0
@DeltaD = 0
Wait(0.5)
EndSub
After that, you can use predefined procedures like Lift_Up, Claw_Close, etc. to control the manipulators. Each of them changes the delta value, and the thread continuously adjusts motor power to reach that position.
Sub Lift_Up
@DeltaA = 650
EndSub
Sub Claw_Close
@DeltaD = 300
Wait(0.3) ' use wait it you want to wait for the action to finish
EndSub
These commands are non-blocking when using the _No_Wait variant, so you can chain multiple movements together in parallel while the thread adjusts in the background.
The End
Congratulations! You have finished the EV3 lesson.
Explore more lessons via the navigation above. For any feedback do not hesitate to contact. Contact here
© 2025 - 2025 HyperLine Robotics. All Rights Reserved.