====== Pixy2 Python tutorial ====== Pixy2 can be used in combination with different hardware platforms, which makes it such a versatile and powerful device. Among these platforms are widely used platforms like Raspberry Pi and LEGO Mindstorms EV3. If you like to program in Python or MicroPython on any of these platforms, this is your resource to find out how. Each platform has its own characteristics. The way of communicating between Pixy2 and the platform is an important one. For instance, using Raspberry Pi communication goes via USB. If your using LEGO Mindstorms EV3 then you have to use I2C serial communication and connect Pixy2 with the cable delivered with the LEGO version of Pixy2. In this tutorial we will describe the following platforms: * LEGO Mindstorms EV3 using Python on the ev3dev operating system. * LEGO Mindstorms EV3 using MicroPython with PyBricks. * Raspberry Pi: using USB and the libpixyusb2 library. This tutorial belongs to Pixy2 and Pixy2.1. If you own the previous Pixy, go to the chapter "Pixy for LEGO Mindstorms" in the tutorial [[https://github.com/KWSmit/Pixy_ev3dev|over here]], written by one of our customers which explains how to use Pixy on LEGO Mindstorms EV3. ===== LEGO Mindstorms EV3 ===== ==== Python3 ==== If you like to program in Python3, then ev3dev is your best choice. Ev3dev is a Debian Linux-based operating system that runs on several LEGO® Mindstorms compatible platforms including the LEGO® MINDSTORMS EV3 and the Raspberry Pi-powered BrickPi and PiStorms. Just write the image of the ev3dev operating system on a SD-card, put in in your EV3-brick and turn it on. The [[https://www.ev3dev.org/|ev3dev website]] gives a clear explanation how to use it. To follow this tutorial you need a basic understanding of ev3dev. ==== MicroPython ==== A plus for using MicroPython on your EV3 is that it runs a lot faster. If you want to use MicroPython then [[https://pybricks.com|PyBricks]] is the best solution. PyBricks is approved by the LEGO Group and you can find downloads on their LEGO Education website. If you like to use the latest version of PyBricks, you better download it from the [[https://pybricks.com|PyBricks website]]. Follow the instructions on the [[https://pybricks.com/install/mindstorms-ev3/installation/|EV3 installation]] page. ==== pixycamev3 ==== To make programming more easy for you, we developed a Python API to use Pixy2 on the EV3. To use this API you have to install module ''pixycamev3''. The same API can be used with both Python3 and MicroPython. The only difference is the way you install the API. When installed, using our API with Python3 is exactly the same as with MicroPython. But first you have to setup Pixy2. ==== Setting up Pixy2 ==== First configure Pixy2 to communicate over ''I2C''. For this you can use the PixyMon tool. You can find a full reference of PixyMon [[wiki:v2:pixymon_index|here]]. Connect Pixy2 with the USB cable to your computer and run PixyMon. In PixyMon open the configure dialog and select the ''Interface'' tab. If you don't see the ''Interface'' tab, you're probably not running the right firmware on Pixy2. Be sure to run the stock version, instead of the LEGO version. See [[wiki:v2:uploading_new_firmware|this page]] on how to install firmware on Pixy2. {{ :wiki:v2:pixymon_configure_i2c.png?nolink&400 |}} Set ''Data out port'' to ''I2C'' and ''I2C address'' to ''0x54'' (or any other address you like). Save your settings, close the configure dialog, close PixyMon and detach Pixy2 from your computer. ==== Installing pixycamev3 ==== This Python API works both with Python3 and MicroPython. There are two ways you can walk to use the API: === 1. Installing with ''pip'' === > At the moment this method only works for Python3. First login to your EV3 using ''ssh''. Run the following command in a terminal window on your computer: $ ssh robot@xxx.xxx.xxx.xxx where ''robot'' is the default username in ev3dev and ''xxx.xxx.xxx.xxx'' is the IP-address of your EV3. You will be asked for a password. The default password is ''maker''. Be sure to use you're own combination of username and password if you changed the default in ev3dev. When logged in to EV3, you can install the API package on your EV3 with: $ python3 -m pip install pixycamev3 This takes about four minutes on the EV3. ''pip'' is not installed out-of-the-box on ev3dev. You can install ''pip'' with: $ sudo apt install python3-pip Beware this takes about 18 minutes on the EV3! But you can use ''pip'' later on to install other python packages when needed. When package ''pixycamev3'' is installed you're ready to program! Go to the next paragraph [[#Using Python API|Using Python API]]. === 2. Adding the API to your project folder === This method works for both Python3 and MicroPython. In your project folder create a new folder ''pixycamev3''. Visit the repository on [[https://github.com/charmedlabs/pixycamev3/tree/main/pixycamev3|Github]]. Add the file pixy2.py to your folder ''pixycamev3''. The easiest way is to open this file in Github and click on the ''Raw'' button right above the code window. Then select all text of the file and copy it to a new file named ''pixy2.py'' in your ''pixycamev3'' folder. Your project folder structure should look like this: project ├── pixycamev3 │ └── pixy2.py └── main.py The file ''pixy2.py'' works for both Python and MicroPython. When you copied the file you're ready to program! ==== Using pixycamev3 ==== The main object you will need is the ''Pixy2'' class. This object contains all the properties and methods you need to use Pixy2. So first you have to load this object from the ''pixy2'' module: ^ class Pixy2 ^^ | **Parameters:** ^^ | port | The sensor port on the EV3 to which Pixy2 is connected. | | ::: | Valid values in range 1 to 4. | | i2c_address | The I2C address you set in the Pixy2. | | **Returns:** ^^ | Pixy2 object ^^ | **Example:** ^^ | from pixycamev3.pixy2 import Pixy2 pixy2 = Pixy2(port=1, i2c_address=0x54) ^^ Object ''Pixy2'' contains the following methods: ^ %%get_version()%% ^^ | **Description:** ^^ | Get the firmware and hardware version of Pixy2. ^^ | **Parameters:** ^^ | None ^^ | **Returns:** ^^ | Pixy2Version object: ^^ | hardware | Hardware version (int) | | firmware | Firmware version (str) | | firmware_type | Firmware type (int) | | **Example:** ^^ | from pixycamev3.pixy2 import Pixy2 pixy2 = Pixy2(port=1, i2c_address=0x54) # Get version version = pixy2.get_version() print('Hardware: ', version.hardware) print('Firmware: ', version.firmware) ^^ ^ get_resolution() ^^ | **Description:** ^^ | Get the current frame resolution of Pixy2. ^^ | **Parameters:** ^^ | None ^^ | **Returns:** ^^ | PixyResolution object: ^^ | width | Frame width (int) | | height | Frame height (int) | | **Example:** ^^ | from pixycamev3.pixy2 import Pixy2 pixy2 = Pixy2(port=1, i2c_address=0x54) # Get frame resolution resolution = pixy2.get_resolution() print('Frame width: ', resolution.width) print('Frame height: ', resolution.height) ^^ ^ set_lamp(upper, lower) ^^ | **Description:** ^^ | Turn the leds of Pixy2 on or off. ^^ | **Parameters:** ^^ | upper | Upper leds: 0 = off, 1 = on | | lower | Lower led: 0 = off, 1 = on | | **Returns:** ^^ | None ^^ | **Example:** ^^ | from time import sleep from pixycamev3.pixy2 import Pixy2 pixy2 = Pixy2(port=1, i2c_address=0x54) # Turn upper leds on for 2 seconds, then turn off pixy2.set_lamp(1, 0) sleep(2) pixy2.set_lamp(0, 0) ^^ ^ %%set_mode(mode)%% ^^ | **Description:** ^^ | Set mode for Pixy2 (for linetracking) ^^ | **Parameters:** ^^ | mode | Desired mode: | | ::: | %%Pixy2Mode.LINE_MODE_DEFAULT%% | | ::: | %%Pixy2Mode.LINE_MODE_TURN_DELAYED%% | | ::: | %%Pixy2Mode.LINE_MODE_MANUAL_SELECT_VECTOR%% | | ::: | %%Pixy2Mode.LINE_MODE_WHITE_LINE%% | | **Returns:** ^^ | None ^^ | **Example:** ^^ | from pixycamev3.pixy2 import Pixy2, Pixy2Mode pixy2 = Pixy2(port=1, i2c_address=0x54) mode = Pixy2Mode() pixy2.set_mode = mode.LINE_MODE_MANUAL_SELECT_VECTOR ^^ ^ %%get_blocks(mode)%% ^^ | **Description:** ^^ | Gets all detected blocks in the most recent frame. ^^ | **Parameters:** ^^ | sigmap | Sigmap of all 7 signatures for which you wish to receive block data.| | ::: | For example, if you are only interested in block data from | | ::: | signature 1, then sigmap=1. If you are interested inbock data from | | ::: | signatures 1 and 2, then sigmap=3 (1+2). | | %%max_blocks%% | The maximum number of blocks you wish to receive. | | **Returns:** ^^ | %%nr_blocks%% | Number of detected blocks | | blocks | List of Block objects (length = %%nr_blocks%%): | | sig | Signature or color code number | | %%x_center%% | X location of the center of the block | | %%y_center%% | Y location of the center of the block | | width | Width of the block | | height | Height of the block | | angle | Angle of color code in degrees | | %%tracking_index%% | Tracking index of the block | | age | The number of frames the block has been tracked | | **Example:** ^^ | from pixycamev3.pixy2 import Pixy2 pixy2 = Pixy2(port=1, i2c_address=0x54) # Track blocks with signature 1, request just 1 block while True: nr_blocks, blocks = pixy2.get_blocks(1, 1) # Extract data of first (and only) block if nr_blocks >= 1: sig = blocks[0].sig x = blocks[0].x_center y = blocks[0].y_center w = blocks[0].width y = blocks[0].height ^^ ^ %%get_line_tracking_data()%% ^^ | **Description:** ^^ | Get linetracking data (MainFeatures) in the most recent frame. ^^ | **Parameters:** ^^ | None ^^ | **Returns** ^^ | MainFeatures object: ^^ | error | Data error when value True | | %%length_of_payload%% | Number of bytes in payload | | %%number_of_vectors%% | Number of vectors detected | | %%number_of_intersections%% | Number of intersections detected | | %%number_of_barcodes%% | Number of barcodes detected | | vectors | List with Vector objects (length number_of_vectors) | | intersections | List with Intersection objects (length number_of_intersections) | | barcodes | List with Barcode objects (length number_of_barcodes) | | ^^ | Vector object: ^^ | x0 | X location startpoint vector | | y0 | Y location startpoint vector | | x1 | X location endpoint vector | | y1 | Y location endpoint vector | | index | Index of vector in array | | flags | Internal state, used for testing/debugging | | ^^ | Intersection object: ^^ | x | X location of intersection | | y | Y location of intersection | | %%nr_of_branches%% | Number of branches starting at this intersection | | branches | Array with Branch objects (length number_of_branches) | | ^^ | Barcode object: ^^ | x | X location center of barcode | | y | Y location center of barcode | | flags | Internal state, used for testing/debugging | | code | Number of barcode (see Pixy2 wiki) | | ^^ | Branch object: ^^ | index | Index in array | | angle | Angle of branch | | %%angle_byte1%% | Byte1 of angle | | %%angle_byte2%% | Byte2 of angle | | **Example:** ^^ | from pixycamev3.pixy2 import Pixy2 pixy2 = Pixy2(port=1, i2c_address=0x54) # Detect barcodes and print their number while True: data = pixy2.get_linetracking_data() if not data.error: for i in range(0, data.number_of_barcodes) print('Barcode number: ', data.barcodes[i].code) ^^ ^ %%set_next_turn(angle)%% ^^ | **Description:** ^^ | Set direction for turn at the next intersection. After this intersection ^^ | Pixy2 will choose it's default turn again. ^^ | **Parameters:** ^^ | angle | Direction to choose at the next intersection (-180, 180 degrees) | | **Returns:** ^^ | None ^^ | **Example:** ^^ | from time import sleep from pixycamev3.pixy2 import Pixy2 pixy2 = Pixy2(port=1, i2c_address=0x54) # Set next turn to 90 degrees pixy2.set_next_turn(90) ^^ ^ %%set_default_turn(angle)%% ^^ | **Description:** ^^ | Set default direction for all intersections. ^^ | **Parameters:** ^^ | angle | Default direction (-180, 180 degrees) | | **Returns:** ^^ | None ^^ | **Example:** ^^ | from time import sleep from pixycamev3.pixy2 import Pixy2 pixy2 = Pixy2(port=1, i2c_address=0x54) # Set default turn to 0 degrees (straight on) pixy2.set_default_turn(0) ^^ ==== Examples ==== You'll find more practical sample code in the [[https://github.com/charmedlabs/pixycamev3|Github repository]]. ===== Rasberry Pi =====