Comparing LEGO SPIKE Prime Programming: Which Is Best for Robotics Competitions? - 3

Does the Programming Environment Affect Rotation Accuracy? A 90° Test Using the Gyro Sensor When using LEGO SPIKE Prime in robotics competitions, how much does the choice of programming environment affect rotation accuracy? To investigate this, I conducted an experiment comparing different programming environments. Tested Programming Environments I compared the following four environments: Word Blocks (SPIKE App 3) → Download here Python (SPIKE App 3) → Download here Python (Pybricks) → More info C Language (spike-rt) → GitHub repository Robot Configuration For the test, I used a car-type robot with the following setup: Left motor: Port A Right motor: Port B Test Method To compare the environments, I conducted the following test: Use the hub’s gyro sensor to rotate the robot 90° Measure the difference between the target angle (90°) and the actual rotation Perform 10 trials for each environment and calculate the average error Program Code: Word Blocks Python (SPIKE App 3) import motor, motor_pair, time from hub import motion_sensor, port, button motor_pair.pair(motor_pair.PAIR_1, port.A, port.B) motion_sensor.up_face() for i in range(10): # Wait for the left button to be pressed while not button.pressed(button.LEFT): pass while button.pressed(button.LEFT): pass # Reset yaw motion_sensor.reset_yaw(0) time.sleep_ms(50) # Wait for yaw angle to reset start = motion_sensor.tilt_angles()[0]*0.1 # Turn right while (abs(motion_sensor.tilt_angles()[0]*0.1) < 90): motor_pair.move_tank(motor_pair.PAIR_1, 300, -300) # Stop turning motor_pair.stop(motor_pair.PAIR_1,stop=motor.BRAKE) time.sleep_ms(500) stop = abs(motion_sensor.tilt_angles()[0]*0.1) print("start:", start, "stop:", stop) Python (Pybricks) from pybricks.hubs import PrimeHub from pybricks.pupdevices import Motor, ColorSensor, UltrasonicSensor, ForceSensor from pybricks.parameters import Button, Color, Direction, Port, Side, Stop from pybricks.robotics import DriveBase from pybricks.tools import wait, StopWatch hub = PrimeHub() left_motor = Motor(Port.A, Direction.COUNTERCLOCKWISE) right_motor = Motor(Port.B, Direction.CLOCKWISE) for i in range(10): # Wait until button is pressed while not any(hub.buttons.pressed()): wait(10) # Wait for all buttons to be released. while any(hub.buttons.pressed()): wait(10) while not hub.imu.ready(): wait(10) # Reset the IMU hub.imu.reset_heading(0) wait(500) start_heading = hub.imu.heading() # Turn right while abs(start_heading - hub.imu.heading()) < 90: left_motor.run(300) right_motor.run(-300) # Stop turning left_motor.brake() right_motor.brake() wait(500) stop_heading = round(hub.imu.heading(), 1) print("start:", start_heading, "stop:", stop_heading) C Language (spike-rt) #include #include #include #include #include #include "spike/pup/motor.h" #include "spike/pup/colorsensor.h" #include "spike/pup/forcesensor.h" #include "spike/pup/ultrasonicsensor.h" #include "spike/hub/battery.h" #include "spike/hub/button.h" #include "spike/hub/display.h" #include "spike/hub/imu.h" #include "spike/hub/light.h" #include "spike/hub/speaker.h" #include #include "kernel_cfg.h" #include "syssvc/serial.h" #include "math.h" pup_motor_t *motorA; pup_motor_t *motorB; pup_device_t *ColorSensor; pup_device_t *ForceSensor; pup_device_t *UltraSonicSensor; // 0:roll(x) 1:pitch(y) 2:yaw(z) float ang_v[3] = {0}; float imu_offset[3] = {0}; float start_value; // Gyro value at start float stop_value; // Gyro value at stop void Main(intptr_t exinf) { motorA = pup_motor_init(PBIO_PORT_ID_A, PUP_DIRECTION_COUNTERCLOCKWISE); motorB = pup_motor_init(PBIO_PORT_ID_B, PUP_DIRECTION_CLOCKWISE); imu_setup(imu_offset); // Offset calibration int8_t i; for (i = 0; i < 10; i++) { // Wait for left button to be pressed hub_button_t pressed; while(!(pressed&HUB_BUTTON_LEFT)){ hub_button_is_pressed(&pressed); hub_light_on_color(PBIO_COLOR_GREEN); } // Wait for the left button to be released while (pressed & HUB_BUTTON_LEFT) { hub_button_is_pressed(&pressed); hub_light_on_color(PBIO_COLOR_BLUE); } dly_tsk(500*1000); sta_cyc(CYC_HDR); // Start gyro sensor monitoring hub_imu_init(); // Initializing the IMU // Reset yaw ang_v[2] = 0; start_value = ang_v[2]; // Turn right while (fabs(ang_v[2]) < 90) { pup_motor_set_power(motorA, 30); pup_motor_set_power(motorB, -30); } // Stop turning pup_motor_brake(motorA); pup_motor_brake(motorB); dly_tsk(500000); stop_value = ang_v[2]; syslog(LOG_NOTICE, "start: %d.%02d stop: %d.%02d", (int)start_value, (int)((start_value - (int)start_value) * 100), (int)stop_value, (int)(fabs(stop_value

Mar 24, 2025 - 01:21
 0
Comparing LEGO SPIKE Prime Programming: Which Is Best for Robotics Competitions? - 3

Does the Programming Environment Affect Rotation Accuracy? A 90° Test Using the Gyro Sensor
When using LEGO SPIKE Prime in robotics competitions, how much does the choice of programming environment affect rotation accuracy?
To investigate this, I conducted an experiment comparing different programming environments.

Tested Programming Environments

I compared the following four environments:

Robot Configuration

For the test, I used a car-type robot with the following setup:

  • Left motor: Port A
  • Right motor: Port B

Image description

Test Method

To compare the environments, I conducted the following test:

  • Use the hub’s gyro sensor to rotate the robot 90°
  • Measure the difference between the target angle (90°) and the actual rotation
  • Perform 10 trials for each environment and calculate the average error

Program Code:
Word Blocks
Image description
Python (SPIKE App 3)

import motor, motor_pair, time
from hub import motion_sensor, port, button

motor_pair.pair(motor_pair.PAIR_1, port.A, port.B)
motion_sensor.up_face()

for i in range(10):
    # Wait for the left button to be pressed
    while not button.pressed(button.LEFT):
        pass

    while button.pressed(button.LEFT):
        pass   

    # Reset yaw
    motion_sensor.reset_yaw(0)
    time.sleep_ms(50)   # Wait for yaw angle to reset

    start = motion_sensor.tilt_angles()[0]*0.1

    # Turn right
    while (abs(motion_sensor.tilt_angles()[0]*0.1) < 90):
        motor_pair.move_tank(motor_pair.PAIR_1, 300, -300)

    # Stop turning
    motor_pair.stop(motor_pair.PAIR_1,stop=motor.BRAKE)

    time.sleep_ms(500)
    stop = abs(motion_sensor.tilt_angles()[0]*0.1)
    print("start:", start, "stop:", stop)

Python (Pybricks)

from pybricks.hubs import PrimeHub
from pybricks.pupdevices import Motor, ColorSensor, UltrasonicSensor, ForceSensor
from pybricks.parameters import Button, Color, Direction, Port, Side, Stop
from pybricks.robotics import DriveBase
from pybricks.tools import wait, StopWatch

hub = PrimeHub()
left_motor = Motor(Port.A, Direction.COUNTERCLOCKWISE)
right_motor = Motor(Port.B, Direction.CLOCKWISE)

for i in range(10):
    # Wait until button is pressed
    while not any(hub.buttons.pressed()):
        wait(10)
    # Wait for all buttons to be released.
    while any(hub.buttons.pressed()):
        wait(10)

    while not hub.imu.ready():
        wait(10)

    # Reset the IMU
    hub.imu.reset_heading(0)
    wait(500)
    start_heading = hub.imu.heading()

    # Turn right
    while abs(start_heading - hub.imu.heading()) < 90:
        left_motor.run(300)
        right_motor.run(-300)

    # Stop turning
    left_motor.brake()
    right_motor.brake()

    wait(500)
    stop_heading = round(hub.imu.heading(), 1)
    print("start:", start_heading, "stop:", stop_heading)

C Language (spike-rt)

#include 
#include 
#include 

#include 

#include 

#include "spike/pup/motor.h"
#include "spike/pup/colorsensor.h"
#include "spike/pup/forcesensor.h"
#include "spike/pup/ultrasonicsensor.h"

#include "spike/hub/battery.h"
#include "spike/hub/button.h"
#include "spike/hub/display.h"
#include "spike/hub/imu.h"
#include "spike/hub/light.h"
#include "spike/hub/speaker.h"

#include 

#include "kernel_cfg.h"
#include "syssvc/serial.h"
#include "math.h"

pup_motor_t *motorA;
pup_motor_t *motorB;
pup_device_t *ColorSensor;
pup_device_t *ForceSensor;
pup_device_t *UltraSonicSensor;

// 0:roll(x) 1:pitch(y) 2:yaw(z)
float ang_v[3] = {0};
float imu_offset[3] = {0};

float start_value; // Gyro value at start
float stop_value; // Gyro value at stop

void Main(intptr_t exinf)
{
  motorA = pup_motor_init(PBIO_PORT_ID_A, PUP_DIRECTION_COUNTERCLOCKWISE);
  motorB = pup_motor_init(PBIO_PORT_ID_B, PUP_DIRECTION_CLOCKWISE);

  imu_setup(imu_offset); // Offset calibration

  int8_t i;
  for (i = 0; i < 10; i++) {
    // Wait for left button to be pressed
    hub_button_t pressed;
    while(!(pressed&HUB_BUTTON_LEFT)){
      hub_button_is_pressed(&pressed);
      hub_light_on_color(PBIO_COLOR_GREEN);
    }
    // Wait for the left button to be released
    while (pressed & HUB_BUTTON_LEFT) {
      hub_button_is_pressed(&pressed);
      hub_light_on_color(PBIO_COLOR_BLUE);
    }

    dly_tsk(500*1000);
    sta_cyc(CYC_HDR); // Start gyro sensor monitoring
    hub_imu_init(); // Initializing the IMU

    // Reset yaw
    ang_v[2] = 0;
    start_value = ang_v[2]; 

    // Turn right
    while (fabs(ang_v[2]) < 90) {
        pup_motor_set_power(motorA, 30);
        pup_motor_set_power(motorB, -30);
    }

    // Stop turning
    pup_motor_brake(motorA);
    pup_motor_brake(motorB);

    dly_tsk(500000);
    stop_value = ang_v[2];
    syslog(LOG_NOTICE,  "start: %d.%02d stop: %d.%02d",  
      (int)start_value, (int)((start_value - (int)start_value) * 100), 
      (int)stop_value, (int)(fabs(stop_value - (int)stop_value) * 100));
}
  stp_cyc(CYC_HDR); // Stop gyro sensor monitoring
}

void gyro_monitor(intptr_t exinf)
{
  float ang_raw[3]; // IMU angular acceleration
  hub_imu_get_angular_velocity(ang_raw);

  // Offset Correction
  ang_v[0] += (ang_raw[0] - imu_offset[0]) * 0.001;
  ang_v[1] += (ang_raw[1] - imu_offset[1]) * 0.001;
  ang_v[2] += (ang_raw[2] - imu_offset[2]) * 0.001;
}

void imu_setup(float offset[3]){
  dly_tsk(3*1000*1000);

  hub_light_on_color(PBIO_COLOR_ORANGE);

  hub_imu_init(); // Initializing IMU

  float ang_raw[3]; // Raw IMU angular velocity

  // Offset calibration
  for(int i=0; i<1000; i++){
    hub_imu_get_angular_velocity(ang_raw);
    offset[0] += ang_raw[0];
    offset[1] += ang_raw[1];
    offset[2] += ang_raw[2];
    dly_tsk(1*1000);
  }

  offset[0] /= 1000;
  offset[1] /= 1000;
  offset[2] /= 1000;
}

Results: Which Environment Was Most Accurate?

Image description

Here are the average rotation errors (smaller is better):
1️⃣ 6.4° - C Language (spike-rt)