#EV3Basic Using the Mindsensors Sensor Multiplexer with EV3 Basic


David Meego - Click for blog homepagePreviously on this blog, I have mentioned that I mentor for the All Saints’ College Robotics club and volunteer on the Robocup Junior West Australian Committee.

Combining my childhood love of Lego with my career as a software developer has provided me with an exciting, fun filled hobby. Using my knowledge to mentor primary and secondary school students and help them find a love of robotics and software development is extremely fulfilling and a driving force behind why I do what I do.

This fifth article covers using the Mindsensors EV3 Sensor Multiplexer with the EV3 Basic extensions for Microsoft Small Basic.

The Mindsensors EV3 Sensor Multiplexer is a Lego Mindstorms compatible device which allows three sensors to be connected to a single sensor port on the controller brick. Using a single EV3 Sensor Multiplexer will allow a robot to have six sensors rather than the usual limit of four.

Note: The latest version of the EV3SensorMux has a casing over the circuit board and so looks a little different to the images above.

This can be extremely useful as a Robocup Junior Australia Open Rescue robot needs to detect the colour of the rescue capsules in the rescue zone. This would require an additional colour sensor.

While it would be possible to create a robot with only four sensors:

  • Two Colour Sensors for Line Following
  • Ultrasonic Sensor for rescue capsule location and object detection
  • Additional Colour Sensor for rescue capsule detection

The ability to connect one or two more sensors can create a more powerful robot, for example:

  • Two Colour Sensors for Line Following
  • Ultrasonic Sensor for rescue capsule location
  • Additional Colour Sensor for rescue capsule detection
  • Touch Sensor for object detection
  • Optional: Gyro Sensor for improved positional control in rescue zone

Mindsensors provide the drivers (blocks) and samples to use the EV3 Sensor Multiplexer with EV3-G and some other languages (NXC and RobotC), but do not have anything to show how it works with EV3 Basic.

After some initial experimentation and a couple of emails with Reinhard Grafl (the creator of EV3 Basic), I understood enough of how the Sensor.CommunicateI2C() command works with I2C devices to get the EV2 Sensor Multiplexer working.

The following code sample displays the readings from three sensors. It is designed to have the EV3 Sensor Multiplexer plugged into port 4 on the EV3 Brick and have the following sensors connected:

  • Channel 1 – Ultrasonic Sensor
  • Channel 2 – Colour Sensor
  • Channel 3 – Gyro Sensor (currently mounted inverted on my robot)

EV3 Basic

'  ** Sensor MUX Test **

'  By David Musgrave

'  http://WinthropDC.com

'  Last Modified: 26-Jun-2017

' ** Setup Starts Here *******************************************************************************************************

' Initialise Variables
Finished = "False"
Clicks = ""

' Mindsensors.com EV3 Sensor Multiplexer
I2CPort = 4
I2CBus = 80
I2CChannel = 0
I2CAddr = 0
I2CReg = 0
I2CWriteByte = 0
I2CWriteData = Vector.Init(2, 0)
I2CReadByte = 0
I2CReadData = Vector.Init(2, 0)

UltraSonic = 0
Gyro = 0
Light = 0

' ** Subroutines Starts Here *******************************************************************************************************

Sub InitUltrasonic
  I2CChannel = 1
  I2CAddr = I2CBus + 1 * (I2CChannel - 1)
  I2CReg = 82 ' 0x52 Sensor Mode
  I2CWriteByte = 1 + 1
  I2CWriteData = Vector.Init(I2CWriteByte, I2CReg)
  I2CWriteData[1] = 0 ' Ultrasonic Mode 0 = CM
  I2CReadByte = 1
  I2CReadData = Vector.Init(I2CReadByte, 0)
  
  I2CReadData = Sensor.CommunicateI2C(I2CPort, I2CAddr, I2CWriteByte, I2CReadByte, I2CWriteData)
  
  ReadUltrasonic()
EndSub 

Sub ReadUltrasonic ' Out: UltraSonic  in cm
  I2CChannel = 1
  I2CAddr = I2CBus + 1 * (I2CChannel - 1)
  I2CReg = 84 ' 0x54 Sensor Data
  I2CWriteByte = 1 + 0
  I2CWriteData = Vector.Init(I2CWriteByte, I2CReg)
  I2CReadByte = 2
  I2CReadData = Vector.Init(I2CReadByte, 0)

  I2CReadData = Sensor.CommunicateI2C(I2CPort, I2CAddr, I2CWriteByte, I2CReadByte, I2CWriteData)
  UltraSonic = (I2CReadData[1] * 256 + I2CReadData[0]) / 10
EndSub

Sub InitLight
  I2CChannel = 2
  I2CAddr = I2CBus + 1 * (I2CChannel - 1)
  I2CReg = 82 ' 0x52 Sensor Mode
  I2CWriteByte = 1 + 1
  I2CWriteData = Vector.Init(I2CWriteByte, I2CReg)
  I2CWriteData[1] = 0 ' Color Sensor Mode 0 = Reflected
  I2CReadByte = 1
  I2CReadData = Vector.Init(I2CReadByte, 0)
  
  I2CReadData = Sensor.CommunicateI2C(I2CPort, I2CAddr, I2CWriteByte, I2CReadByte, I2CWriteData)
  
  ReadLight()
EndSub 

Sub ReadLight ' Out: Light
  I2CChannel = 2
  I2CAddr = I2CBus + 1 * (I2CChannel - 1)
  I2CReg = 84 ' 0x54 Sensor Data
  I2CWriteByte = 1 + 0
  I2CWriteData = Vector.Init(I2CWriteByte, I2CReg)
  I2CReadByte = 2
  I2CReadData = Vector.Init(I2CReadByte, 0)

  I2CReadData = Sensor.CommunicateI2C(I2CPort, I2CAddr, I2CWriteByte, I2CReadByte, I2CWriteData)
  Light = I2CReadData[1] * 256 + I2CReadData[0]
EndSub
  
Sub InitGyro
  I2CChannel = 3
  I2CAddr = I2CBus + 1 * (I2CChannel - 1)
  I2CReg = 82 ' 0x52 Sensor Mode
  I2CWriteByte = 1 + 1
  I2CWriteData = Vector.Init(I2CWriteByte, I2CReg)
  I2CWriteData[1] = 1 ' Gyro Mode 1 = Rate
  I2CReadByte = 1
  I2CReadData = Vector.Init(I2CReadByte, 0)
  
  I2CReadData = Sensor.CommunicateI2C(I2CPort, I2CAddr, I2CWriteByte, I2CReadByte, I2CWriteData)

  I2CWriteData[1] = 0 ' Gyro Mode 0 = Angle
  
  I2CReadData = Sensor.CommunicateI2C(I2CPort, I2CAddr, I2CWriteByte, I2CReadByte, I2CWriteData)
  
  ReadGyro()
EndSub 

Sub ReadGyro ' Out: Gyro in Degrees
  I2CChannel = 3
  I2CAddr = I2CBus + 1 * (I2CChannel - 1)
  I2CReg = 84 ' 0x54 Sensor Data
  I2CWriteByte = 1 + 0
  I2CWriteData = Vector.Init(I2CWriteByte, I2CReg)
  I2CReadByte = 2
  I2CReadData = Vector.Init(I2CReadByte, 0)

  I2CReadData = Sensor.CommunicateI2C(I2CPort, I2CAddr, I2CWriteByte, I2CReadByte, I2CWriteData)
  Gyro = I2CReadData[1] * 256 + I2CReadData[0]
  If Gyro >= 32768 Then
    Gyro = Gyro - 65536
  EndIf  
  Gyro = -Gyro ' Inverted due to mounting position
EndSub

Sub ResetGyro
  ReadGyro()
  While Gyro <> 0 
    InitGyro()
    Program.Delay(15)
  EndWhile  
EndSub

' ** Main Program Starts Here *******************************************************************************************************

LCD.Clear()
LCD.Write( 0*8, 0*10, "SensorMUX Test")
LCD.Write( 0*8, 2*10, "Port: " + I2CPort)
LCD.Write(10*8, 2*10, "Address: " + I2CBus)

InitGyro()
InitUltrasonic()
InitLight()
While Finished = "False"
  ReadUltrasonic()
  LCD.Write(0*8, 4*10, "Ultrasonic: "+ Text.GetSubText("     "+(Ultrasonic),Text.GetLength((Ultrasonic)),6) +" cm")
  ReadGyro()
  LCD.Write(0*8, 6*10, "Gyro      : "+ Text.GetSubText("     "+(Gyro),Text.GetLength((Gyro)),6))
  ReadLight()
  LCD.Write(0*8, 8*10, "Light     : "+ Text.GetSubText("     "+(Light),Text.GetLength((Light)),6))

  Clicks = Buttons.GetClicks()
  If Text.IsSubText(Clicks, "E") Then
    Finished = "True"
  EndIf
EndWhile 

Conclusions

For the conclusion, I thought I would try to explain how the Sensor.CommunicateI2C() works with the I2C protocol. The syntax is as follows:

ReadData = Sensor.CommunicateI2C(Port, Address, WriteByte, ReadByte, WriteData)

The values are as follows:

ReadData
This is an array of bytes (values 0 to 255) returned. If the data returned is more than one byte you might need to combine the values together as a High byte and Low byte. It is best practice to initialise the array to zeros before making the call.

Port
This is the port of the EV3 Controller Brick that the I2C device is plugged into.

Address
This is the unique address (0 to 127) for the I2C slave device on the I2C bus. Note: For EV3 Basic this is expressed in Words (16 bit increments). Each device has a default address that it comes with. It is easiest to use the default address even though there is a way to change it. The documentation usually provides this address in hexadecimal in a range of 0x00 to 0xFF (bytes – 8 bit increments). For example: The documentation shows that Channel 1 of the EV3SensorMux is at 0xA0. This is 160 in 8 bit decimal, so you must divide by 2 for the address in 16 bit decimal = 80. Channels 2 and 3 are located at 0xA2 and 0xA4, which converts to 81 and 82 respectively.

WriteByte
The number of bytes of data to send to the device. You can send up to 31 bytes of user data. However, the first byte is the address of the first register to write data to or read data from.

ReadByte
The number of bytes of data to read from the device. At least one byte must be returned, even if you do not use it.

WriteData
This is an array of bytes to send to the device with the first byte being the address of the first register.

So to write a single byte to register 0x52 (82) of value X, your settings should be:

WriteByte = 2, WriteData[0] = 82, WriteData[1] = X, ReadByte = 1, ReadData[0] = 0

Or to read two bytes from register 0x54 (84), your settings should be:

WriteByte = 1, WriteData[0] = 84, ReadByte = 2, ReadData[0] = 0, ReadData[1] = 0

I hope this makes it easier to understand the code example above. Once I worked out that you needed to halve the device address after converting it to decimal, everything started to work. Please refer to the documentation published by Mindsensors for further information on using the EV3 Sensor Multiplexer.

 

For more information on robotics and the EV3 Basic extensions to Microsoft Small Basic, check out the following links:

In the next article, we will discuss how to use the Mindsensors Motor Multiplexer with EV3 Basic.

David

This article was originally posted on http://www.winthropdc.com/blog.

Advertisements

Please post feedback or comments

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s