Complete guide to using all of the features of the MotorGo Plink Python API
- Table of Contents
- Getting Started
- Accessing Motor Channels
- Reading Encoder Data
- Controlling Motors
- Reading IMU Data
- Reading Light and Range Sensor Data
- Examples
To start using the MotorGo Python API, first import your MotorGo board from the motorgo
module:
from motorgo import Plink
Next, create an instance of the board you imported:
plink = Plink()
Optionally, you can configure the communication parameter for the board:
plink = Plink(frequency = 200, timeout = 1.0)
Frequency defines the frequency of data transmission to the MotorGo board. Reducing the frequency results in less CPU usage on the MotorGo and Pi. The frequency may not be stable above 200 Hz. Timeout defines the time in seconds to wait for a response from the MotorGo board before attempting to reset communications.
To begin communication, run the following command:
plink.connect()
The MotorChannel
objects are the primary interface for controlling the motors and reading their corresponding encoder data. The MotorChannel
objects are accessible as:
plink.channel1
plink.channel2
plink.channel3
plink.channel4
You can save a reference to the MotorChannel
objects as local variables for convenience. For example:
left_drive_wheel = plink.channel1
right_drive_wheel = plink.channel2
The encoder data can be accessed from the MotorChannel
objects in the Plink
object. The MotorChannel
objects are accessible as:
To read the encoder data, simply access the position
and velocity
attributes of the MotorChannel
object:
left_position = left_drive_wheel.position # Position, in radians
left_velocity = left_drive_wheel.velocity # Velocity, in radians/sec
channel_3_position = plink.channel3.position
channel_3_velocity = plink.channel3.velocity
print(f"Left wheel: {left_position}\t {left_velocity}")
print(f"Channel 3: {channel_3_position}\t {channel_3_velocity}")
Note that the forward direction of the position is dependent on the direction that the motor is connected to the MotorGo and the direction the encoder is connected to the motor.
The Plink supports two motor control modes: ControlMode.POWER
and ControlMode.VELOCITY
.
In power control mode, the motor is controlled by directly setting the power level. The power level is a value between -1.0 and 1.0, where -1.0 is full reverse, 0.0 is stopped, and 1.0 is full forward. To configure a motor channel to power control mode, set the control_mode
attribute of the MotorChannel
object to ControlMode.POWER
.
from motorgo import ControlMode
left_drive_wheel.control_mode = ControlMode.POWER
To set the power level of the motor, set the power
attribute of the MotorChannel
object to a value between -1.0 and 1.0.
left_drive_wheel.power = 0.5
In velocity control mode, the motor is controlled by setting the desired velocity in rad/s. To configure a motor channel to velocity control mode, set the control_mode
attribute of the MotorChannel
object to ControlMode.VELOCITY
.
from motorgo import ControlMode
left_drive_wheel.control_mode = ControlMode.VELOCITY
Next, you must configure the velocity PID controller parameters for the motor:
left_drive_wheel.set_velocity_pid_gains(p = 1.0, i = 0.0, d = 0.0, output_ramp = None, lpf = None)
The output_ramp
can be set to limit the rate of change of the motor power output. The lpf
parameter can be set to apply a low-pass filter to the velocity setpoint. You can set any of the parameters to None
to use the default values.
Finally, set the desired velocity of the motor by setting the velocity
attribute of the MotorChannel
object to the desired velocity in rad/s.
left_drive_wheel.velocity = 1.0
If the motor seems to be spinning at the top speed regardless of the velocity setpoint, you may need to flip the sign of the PID gains, as the motor may be spinning in the opposite direction of the encoder.
The data from the onboard IMU can be accessed through the IMU
object in the Plink
object.
imu = plink.imu
The IMU
object provides the raw IMU data from the gyroscope, accelerometer, and magnetometer.
gyro = imu.gyro
accel = imu.accel
mag = imu.mag
The data is returned as numpy.ndarray
objects, each containing 3 elements corresponding to the x, y, and z axes. The coordinate frame is on the MotorGo board. The gyroscope data is in rad/s, the accelerometer data is in m/s^2, and the magnetometer data is in uT.
In addition to the raw data, the MotorGo Python API filters the IMU data to compute the orientation of the MotorGo relative to the Earth's gravity vector. You can access the orientation of the Plink board as a quaternion:
orientation = imu.orientation # Returns a numpy.ndarray containing [w, x, y, z]
You can also read the gravity vector, relative to the MotorGo board, as a numpy.ndarray containing [x, y, z]:
gravity_vector = imu.gravity_vector
Since the QWIIC ports on the MotorGo are connected to the Raspberry Pi I2C bus, you can access the sensors directly from the Raspberry Pi.
Once you have connected the sensor, you can confirm that the Raspberry Pi can detect the sensor by running the following command:
i2cdetect -y 1
You should see the address of the sensor in the output. For example, the BH1750 light sensor has an address of 0x23
.
You can read the light sensor data in Python with the following code:
import board
import adafruit_bh1750
i2c = board.I2C() # uses board.SCL and board.SDA
# i2c = board.STEMMA_I2C() # For using the built-in STEMMA QT connector on a microcontroller
sensor = adafruit_bh1750.BH1750(i2c)
while True:
print("%.2f Lux" % sensor.lux)
time.sleep(0.2)
You can read the range sensor data in Python with the following code:
import board
import adafruit_vl53l4cx
i2c = board.I2C() # uses board.SCL and board.SDA
# i2c = board.STEMMA_I2C() # For using the built-in STEMMA QT connector on a microcontroller
vl53 = adafruit_vl53l4cx.VL53L4CX(i2c)
print("VL53L4CX Simple Test.")
vl53.start_ranging()
while True:
while not vl53.data_ready:
pass
vl53.clear_interrupt()
print("Distance: {} cm".format(vl53.distance))
You can find full examples of using the MotorGo Plink Python API in the examples
directory of this repository.