The Kria KR260 Robotics Starter Kit was built specifically for robotics application development, so what better peripheral to get running than a motor? In my past few project posts using the KR260, I've mapped out the pins for the PMODs and Raspberry Pi GPIO header to make them available to the Linux userspace via AXI GPIO in the programmable logic (PL) of the Kria. This has in part been in preparation to use my Pmod HB3 H-bridge motor driver boards with encoder feedback inputs from Digilent.
I'm a fan of the HB3 PMODs because they're such simple and compact little boards, but are still easy to use with a breadboard for development.
In terms of motors with encoder capabilities, I prefer those that have a magnetic wheel with multiple hall effect sensors to be able to calculate the speed and direction of the motor like the N20 DC motors from Adafruit. They are a perfect match to use with the HB3 PMOD H-bridge to read the output of the two hall effect sensors that are tracking it magnetic wheel.
Hardware SetupAnother nice thing about the HB3 PMOD boards is that they only take up one row on a PMOD connector, and the Kria KR260 could drive up to 8 individual motors using HB3s. So with one of my HB3s connected to the upper row of PMOD1 on the KR260, I used a breadboard as a connector interface between the HB3 and the N20 DC motor just for the sake of an easy demo setup versus putting female header pins on the two hall effect sensor output lines (the green and yellow wires on the N20 motor) and the encoder circuit supply lines (black Vcc wire and blue Gnd wire) of the N20 motor to connect them to the male header pins for sensor feedback inputs (J5) on the HB3 PMOD.
The screw terminals on the J2 and J3 connectors of the HB3 are for the motor drive. J2, labeled as M+ and M-, is for the motor itself (the white and red wires respectively on the N20 motor). Then J3, labeled as Vm and GND, are for the power supply to drive the motor. Since this particular N20 DC motor needs 6V and about 0.5A, I just have jumpers in the screw terminals connected to alligator clips from my bench-top power supply.
Overall, the hardware connections for this setup are outlined below:
As previously mentioned, the PMODs on the KR260 baseboard are connected via AXI GPIO IP blocks in the programmable logic of the Kria K26 to make them accessible in the Linux userspace. I covered this part of the design in-depth in my previous project post here.
I am simply loading that bitstream and device tree overlay from that design here. Since I already have those design file uploaded to my KR206, the PL design shows up just like an accelerated application would using the xmutil commands:
xilinx-kr260-starterkit-20221:~$ sudo xmutil listapps
Unload the default application then load the PL design for the PMOD GPIO which flashes that bitstream onto the PL of the Kria and loads its device tree overlay:
xilinx-kr260-starterkit-20221:~$ sudo xmutil unloadapp
xilinx-kr260-starterkit-20221:~$ sudo xmutil loadapp kr260_gpio
When the device tree overlay loads, the terminal will print out as such indicating the new device tree nodes for each of the AXI GPIO IP blocks are now present in the system and applications in the Linux userspace can now access the PMODs:
The HB3 PMOD H-bridge circuit is driven with two GPIO siganls: an enable signal (EN) and a direction set signal (DIR). As can be seen in the schematic for the HB3 below, the enable single sets a pair of AND gates to logic level high that turn on one of two MOSFETs to complete a circuit and provide power to the motor. The direction set signal is on the other input of the pair of AND gates to determine which of the two MOSFETs is turned on. This sets the polarity of the power provided to the motor, ultimately dictating which direction the motor turns in (forward when positive polarity power is supplied, and reverse when negative polarity power is supplied).
In order to prevent the H-bridge circuit from accidentally being shorted out, it is very important to never change the logic level of the direction set signal (DIR) when the enable signal (EN) is set high/logic level 1. This means the motor cannot change direction while spinning, power must be removed before switching direction.
Furthermore, the enable signal can be driven with a pulse-width modulated signal in order to control the speed of the motor. The higher the duty cycle of the PWM signal, the faster the motor will spin where 100% (always on) PWM is the motor's maximum speed. I didn't bother with making the enable signal in my code a PWM signal, but it's worth noting that some tweaks to the aforementioned PL design would be required since a PWM signal is not just a straight GPIO interface in this context.
Then while the motor is being driven by the EN and DIR outputs, the sensor A (SA) and sensor B (SB) feedback pins are reading the current state of the hall effect sensors placed near the magnetic wheel. Hall effect sensors simply output a voltage level directly proportional to the strength of the magnetic field it subjected to.
The magnetic wheel on the N20 motor is simply a gear wheel with a magnet placed at a certain point on it similar to the photo above (the photo above has two magnets while the gear wheel on the N20 only has one). The two hall effect sensors are placed 90˚ (π/4) apart around the wheel and each of them output a logic level 1 when the magnet on the gear wheel is passing in front of it. While there is a certain amount of time the magnet will be detected by both sensors, the sensor that starts output a logic level 1 first indicates which direction the magnet came from.
In this case, when hall effect sensor B reads a logic level 1 before hall effect sensor A then the motor is spinning in the forward direction (positive polarity power is being supplied to it). And vice versa: when sensor A read logic level 1 before sensor B, the motor is spinning in the reverse direction (negative polarity power is being supplied to it).
Then the total duration between when sensor A or sensor B start reading logic level 1s to the next time they start reading logic level 1s can be measured/timed and converted into revolutions per minute (RPMs).
Therefore, the C application to control the motor via the HB3 PMOD must set the direction and enable signal outputs, then read back the state of the two hall effect sensors on the sensor A and B feedback pins for a certain duration to calculate the speed and direction the motor is spinning in. See my attached C file below for my demo implementation of the described logic above.
The reason I've taken the time to describe the required logic of the C application in terms of the N20's encoder circuit functionality is because there are several ways to implement it. I did it the easy way by polling the sensor A and B feedback lines from the HB3 for a given direction for the sake of a demo, but another common way is to set one of the sensor feedback lines as an interrupt and only measure for one calculated rotation. Use whatever method makes sense for your needs in a project.
Linux Application Development on KR260While there are a few different ways to develop a Linux application for the Kria, the GPIO for driving an H-bridge motor controller circuit and reading back encoder data is simple enough in this case that writing the C code in a text editor and compiling it natively on the Kria using GCC was the easiest route.
First, GCC needs to be installed on the Kria as it is not included in the PetaLinux build by default. This simply requires using the dnf package manager to install the core SDK package group:
xilinx-kr260-starterkit-20221:~$ sudo dnf install packagegroup-core-sdk
While vi on the Kria itself was an option to write the application C code, I chose to use my favorite (yet sadly discontinued) text editor on my host machine then transfer the source file to the Kria using the file transfer command scp
:
whitneyknitter@Whitneys-MBP motor_driver_2202-1 % scp motor_controller.c petalinux@<KR260 IP address>:/home/petalinux/
Testing the Motor Controller ApplicationSince using Sysfs to access the GPIOs requires root user access and the root user is not enabled in the Linux image for the Kria boards by default (I'll fix that in a later project post), enter the root user using the following command:
xilinx-kr260-starterkit-20221:~$ sudo -i
Create a directory for the application and its source code (optional):
root@xilinx-kr260-starterkit-20221:~$ mkdir -p motor_controller
root@xilinx-kr260-starterkit-20221:~$ cd ./motor_controller/
Copy over the source file from regular user:
root@xilinx-kr260-starterkit-20221:~/motor_controller# cp /home/petalinux/motor_controller.c ./
Compile it using GCC and run the output application (again, be sure you have the bitstream and device tree overlay for the PMOD AXI GPIO loaded as outlined here or the application will crash since it wouldn't be able to find the PMODs):
root@xilinx-kr260-starterkit-20221:~/motor_controller# gcc motor_controller.c -o motor_controller
root@xilinx-kr260-starterkit-20221:~/motor_controller# ./motor_controller
Since my first version of the motor controller C code simply printed out the encoder feedback data, I was able to see exactly how the magnet passing in front of one hall effect before the other caused the serial stream of 1's coming from that sensor to lead the serial stream of 1's coming from the other hall effect sensor.
It was also interesting to see that serial stream of 1's coming from the sensors was much longer initially as the motor was getting up to speed (since I have the enable pin set high the whole time which equates to a 100% duty cycle).
Then my final version of the C application code measured and calculated the direction and speed of the motor and printed it, accounting for the 1:100 gear ratio and multiple ticks read on the magnetic wheel.
While this was a very simple implementation of a motor with encoder, it was still very fun to see my KR260 successfully making something move. I'm excited to get more motors hooked up and driving my Lego robot's chassis!
Comments