Using CBDs with LEGO MINDSTORMS EV3

The LEGO MINDSTORMS EV3 can be fully accessed via Python-code. Combined with the usefulness of CBDs for continuous embedded systems, it stands to reason the CBD simulator can be used to access the EV3 system. To do so, pybricks (micropython) will be used.

In order to do so, follow these installation instructions from the pybricks website. This creates a (bootable) flashed microSD card that can run Python code. Simply write your CBD models and start your simulation!

For convenience, some building blocks are prebuild in this pyCBD.lib.ev3 module.

Set of simple Blocks to use in combination with LEGO Mindstorms EV3.

Requires Pybricks to be installed. See also the documentation at

https://pybricks.com/ev3-micropython

Warning

Brick sounds are not permitted, as they delay the simulation. It is also unclear if multithreading is possible to allow for this.

Note

Because drawing features are quite complicated and use-case specific, no block for drawing to the screen is included. If required, this needs to be created.

Note

It does not make sense to use these blocks in combination with precise state events, as the event has already happened and rewinding is not useful.

class pyCBD.lib.ev3.BrickLightBlock(block_name)[source]

Bases: pyCBD.Core.BaseBlock

Block to change the light of the EV3 Brick.

Parameters

block_name (str) – The name of the block.

Input Ports

IN1 – The value of the light. Must be a Color or None to turn off.

compute(curIteration)[source]

Computes this block’s operation, based on its inputs and store it as an output signal.

Parameters

curIteration (int) – The iteration at which we must compute this value.

class pyCBD.lib.ev3.BatteryVoltageBlock(block_name, starting=None)[source]

Bases: pyCBD.Core.BaseBlock

Block that outputs the current EV3 Brick’s voltage.

Parameters
  • block_name (str) – The name of the block.

  • starting (numeric) – The starting voltage of the Brick. When None, the Voltage is outputted in an absolute value. Otherwise, a percentage is used. When set, must be larger than 0.

Output Ports

OUT1 – The voltage of the EV3 Brick. Can be absolute or relative (percentage).

compute(curIteration)[source]

Computes this block’s operation, based on its inputs and store it as an output signal.

Parameters

curIteration (int) – The iteration at which we must compute this value.

class pyCBD.lib.ev3.TouchSensorBlock(block_name, port_name)[source]

Bases: pyCBD.Core.BaseBlock

Block to check if a touch sensor is pressed.

Parameters
  • block_name (str) – The name of the block.

  • port_name (str) – The name of the sensor port. This is a number between 1 and 4.

Output Ports
OUT1 – Boolean value indicating if the button is pressed (True)

or not (False).

compute(curIteration)[source]

Computes this block’s operation, based on its inputs and store it as an output signal.

Parameters

curIteration (int) – The iteration at which we must compute this value.

class pyCBD.lib.ev3.ColorSensorBlock(block_name, port_name)[source]

Bases: pyCBD.Core.BaseBlock

Block to compute the color reflection of a surface.

Parameters
  • block_name (str) – The name of the block.

  • port_name (str) – The name of the sensor port. This is a number between 1 and 4.

Output Ports
  • OUT1 – The amount of red reflected light.

  • OUT2 – The amount of green reflected light.

  • OUT3 – The amount of blue reflected light.

Note

Can cause inconsistent and invalid results when the AmbientLightSensorBlock is also used on the same port.

compute(curIteration)[source]

Computes this block’s operation, based on its inputs and store it as an output signal.

Parameters

curIteration (int) – The iteration at which we must compute this value.

class pyCBD.lib.ev3.AmbientLightSensorBlock(block_name, port_name)[source]

Bases: pyCBD.Core.BaseBlock

Block to compute the amount of ambient light.

Parameters
  • block_name (str) – The name of the block.

  • port_name (str) – The name of the sensor port. This is a number between 1 and 4.

Output Ports

OUT1 – The amount of ambient light.

Note

Can cause inconsistent and invalid results when the ColorSensorBlock is also used on the same port.

compute(curIteration)[source]

Computes this block’s operation, based on its inputs and store it as an output signal.

Parameters

curIteration (int) – The iteration at which we must compute this value.

class pyCBD.lib.ev3.InfraredDistanceSensorBlock(block_name, port_name)[source]

Bases: pyCBD.Core.BaseBlock

Block to compute the distance to an object, using an infrared sensor.

Parameters
  • block_name (str) – The name of the block.

  • port_name (str) – The name of the sensor port. This is a number between 1 and 4.

Output Ports

OUT1 – The distance to an object.

compute(curIteration)[source]

Computes this block’s operation, based on its inputs and store it as an output signal.

Parameters

curIteration (int) – The iteration at which we must compute this value.

class pyCBD.lib.ev3.InfraredButtonSensorBlock(block_name, port_name, channel)[source]

Bases: pyCBD.Core.BaseBlock

Block to compute the input of a remote.

Parameters
  • block_name (str) – The name of the block.

  • port_name (str) – The name of the sensor port. This is a number between 1 and 4.

  • channel (int) – The channel on the remote.

Output Ports

OUT1 – The button list. Should not be used for mathematical computations.

compute(curIteration)[source]

Computes this block’s operation, based on its inputs and store it as an output signal.

Parameters

curIteration (int) – The iteration at which we must compute this value.

class pyCBD.lib.ev3.UltrasonicSensorBlock(block_name, port_name)[source]

Bases: pyCBD.Core.BaseBlock

Block to compute the distance to an object, using an ultrasonic sensor.

Parameters
  • block_name (str) – The name of the block.

  • port_name (str) – The name of the sensor port. This is a number between 1 and 4.

Output Ports

OUT1 – The distance to an object.

Note

The sensor does not turn off after measuring a distance. Because of a presumed high-rate CBD simulation, continuously turning it off is bad for performance and may cause the sensor to freeze.

This results in the sensor causing more inference with other ultrasonic sensors.

compute(curIteration)[source]

Computes this block’s operation, based on its inputs and store it as an output signal.

Parameters

curIteration (int) – The iteration at which we must compute this value.

class pyCBD.lib.ev3.GyroscopicSpeedSensorBlock(block_name, port_name, direction=Direction.CLOCKWISE)[source]

Bases: pyCBD.Core.BaseBlock

Block to compute the rotational velocity, using a gyroscopic sensor.

Parameters
  • block_name (str) – The name of the block.

  • port_name (str) – The name of the sensor port. This is a number between 1 and 4.

  • direction (Direction) – Whether the sensor should be rotating clockwise or counter-clockwise. Defaults to CLOCKWISE.

Output Ports

OUT1 – The rotational velocity in deg/s.

compute(curIteration)[source]

Computes this block’s operation, based on its inputs and store it as an output signal.

Parameters

curIteration (int) – The iteration at which we must compute this value.

class pyCBD.lib.ev3.GyroscopicAngleSensorBlock(block_name, port_name, direction=Direction.CLOCKWISE, resettable=False)[source]

Bases: pyCBD.Core.BaseBlock

Block to compute an angle, using a gyroscopic sensor.

Parameters
  • block_name (str) – The name of the block.

  • port_name (str) – The name of the sensor port. This is a number between 1 and 4.

  • direction (Direction) – Whether the positive rotation should be clockwise or counter-clockwise. Defaults to CLOCKWISE.

  • resettable (bool) – When True, an input is added on which the angle can be changed. Defaults to False.

Input Ports

IN1 – New value for the angle in deg. Optional port if the angle can be reset.

Output Ports

OUT1 – The angle in deg.

compute(curIteration)[source]

Computes this block’s operation, based on its inputs and store it as an output signal.

Parameters

curIteration (int) – The iteration at which we must compute this value.

class pyCBD.lib.ev3.MotorBlock(block_name, port_name, direction=Direction.CLOCKWISE, gears=None, control=None)[source]

Bases: pyCBD.Core.BaseBlock

Block that drives a single Motor.

Parameters
  • block_name (str) – The name of the block.

  • port_name (str) – The name of the actuator port. This is a letter between A and D.

  • direction (Direction) – Whether the positive rotation should be clockwise or counter-clockwise. Defaults to CLOCKWISE.

  • gears (list) – Additional list of gears that are linked to the motor, to allow for better control. Defaults to None (i.e., the empty list).

  • control (Control) – The Motors themselves use a PID controller. To fully manipulate their behaviour, use the Control class.

Input Ports

IN1 – The motor velocity in deg/s. Use 0 to brake the rotation.

compute(curIteration)[source]

Computes this block’s operation, based on its inputs and store it as an output signal.

Parameters

curIteration (int) – The iteration at which we must compute this value.

class pyCBD.lib.ev3.MotorSpeedSensorBlock(block_name, port_name, direction=Direction.CLOCKWISE, gears=None, control=None)[source]

Bases: pyCBD.Core.BaseBlock

Block to compute the rotational velocity of a motor.

Parameters
  • block_name (str) – The name of the block.

  • port_name (str) – The name of the motor port. This is a letter between A and D.

  • direction (Direction) – Whether the sensor should be rotating clockwise or counter-clockwise. Defaults to CLOCKWISE.

  • gears (list) – Additional list of gears that are linked to the motor, to allow for better control. Defaults to None (i.e., the empty list).

  • control (Control) – The Motors themselves use a PID controller. To fully manipulate their behaviour, use the Control class.

Output Ports

OUT1 – The rotational velocity in deg/s.

compute(curIteration)[source]

Computes this block’s operation, based on its inputs and store it as an output signal.

Parameters

curIteration (int) – The iteration at which we must compute this value.

class pyCBD.lib.ev3.MotorAngleSensorBlock(block_name, port_name, direction=Direction.CLOCKWISE, resettable=False, gears=None, control=None)[source]

Bases: pyCBD.Core.BaseBlock

Block to compute an angle of a Motor.

Parameters
  • block_name (str) – The name of the block.

  • port_name (str) – The name of the motor port. This is a letter between A and D.

  • direction (Direction) – Whether the positive rotation should be clockwise or counter-clockwise. Defaults to CLOCKWISE.

  • resettable (bool) – When True, an input is added on which the angle can be changed. Defaults to False.

  • gears (list) – Additional list of gears that are linked to the motor, to allow for better control. Defaults to None (i.e., the empty list).

  • control (Control) – The Motors themselves use a PID controller. To fully manipulate their behaviour, use the Control class.

Input Ports

IN1 – New value for the angle in deg. Optional port if the angle can be reset.

Output Ports

OUT1 – The angle in deg.

compute(curIteration)[source]

Computes this block’s operation, based on its inputs and store it as an output signal.

Parameters

curIteration (int) – The iteration at which we must compute this value.

class pyCBD.lib.ev3.DifferentialDrive(block_name, left_port_name, right_port_name, wheel_diameter, axle_length, ldirection=Direction.CLOCKWISE, rdirection=Direction.CLOCKWISE, left_gears=None, right_gears=None, l_control=None, r_control=None, v_control=None, h_control=None)[source]

Bases: pyCBD.Core.BaseBlock

Implements the builtin Differential Drive Odometry from Pybricks.

This assumes your robot has two nonholonomic wheels (and an optional ball caster), both wheels are connected to their own motor, but virtually located among the same axis. The robot center is the center of both wheels.

This block ignores slipping and skidding and mainly should only be used as “estimation” information, as LEGO is not precise enough for exact, accurate data.

Parameters
  • block_name (str) – The name of the block.

  • left_port_name (str) – The name of the left motor port. This is a letter between A and D.

  • right_port_name (str) – The name of the right motor port. This is a letter between A and D.

  • wheel_diameter (float) – The diameter of the wheel.

  • axle_length (float) – The distance between both wheels.

  • ldirection (Direction) – Whether the left motor’s positive rotation should be clockwise or counter-clockwise. Defaults to CLOCKWISE.

  • rdirection (Direction) – Whether the right motor’s positive rotation should be clockwise or counter-clockwise. Defaults to CLOCKWISE.

  • left_gears (list) – Additional list of gears that are linked to the left motor, to allow for better control. Defaults to None (i.e., the empty list).

  • right_gears (list) – Additional list of gears that are linked to the right motor, to allow for better control. Defaults to None (i.e., the empty list).

  • l_control (Control) – The Motors themselves use a PID controller. To fully manipulate their behaviour, use the Control class. This value alters the left motor’s control.

  • r_control (Control) – The Motors themselves use a PID controller. To fully manipulate their behaviour, use the Control class. This value alters the right motor’s control.

  • v_control (Control) – The Motors themselves use a PID controller. To fully manipulate their behaviour, use the Control class. This value alters the linear velocity control.

  • h_control (Control) – The Motors themselves use a PID controller. To fully manipulate their behaviour, use the Control class. This value alters the rotational velocity control.

Input Ports
  • IN1 – The linear velocity in mm/s.

  • IN2 – The angular velocity (top view) in deg/s. This is not the wheel rotation velocity.

Warning

You cannot manipulate the motors individually while this block is active.

compute(curIteration)[source]

Computes this block’s operation, based on its inputs and store it as an output signal.

Parameters

curIteration (int) – The iteration at which we must compute this value.