Brushless Motors Torque Controlling on Raspberry PI

Here I’m going to share how to use a Raspberry Pi to command SOLO through its UART line using the Python Library written for Raspberry Pi for SOLO, in short, the Raspberry Pi will be acting as a supervisory unit, sending high-level commands like the Torque reference to SOLO, and once SOLO receives the command through its UART line from Raspberry Pi, it will do all the rest automatically by following the reference Torque.

In This code, the Torque controlling of the BLDC motors is achieved by using the HALL sensors mounted on the BLDC motor so that using their outputs SOLO can estimate the mechanical position of the Rotor of the BLDC and subsequently measures the Electrical angle of the shaft which is used in FOC and finally controlling the Torque of the BLDC by measuring the propper current fed into the Motor, the current that acts in Torque generation in BLDC motors if the Motor controller operates in FOC, is called “Quadrature Current” and it’s shown with “Iq”, the Iq although is fundamentally a component of AC current inside the Brushless Motor but it has a linear relationship with the real torque of the Motor based on:

Brushless Motor’s Torque [N.m] = Iq Current [A] x Motor’s Torque Constant[N.m/A]

So basically the Torque is the Iq multiplied by a constant that is known as the Torque constant and it can be found (or measured) on the datasheet of the BLDC used, in this article for the motor we are using the Torque Constant is 0.08 [N.m/A].

In the Python code above, the Raspberry Pi initially sets the Iq Reference at 3.512 Amps which practically means 0.28 N.m of Torque (3.512 * 0.08) on our BLDC, then Raspberry Pi commands SOLO to stop the motor for a while and this time changes the direction of Rotation and applies a new Iq reference of 2.225 Amps or around 0.178 N.m of Torque, that’s why you see the sign of Iq is positive in case of 3.512A and it gets negative for 2.225A reference as the direction has been changed.

#   Title: Torque Control of a Brushless Motor with RASPBERRY-PI and SOLO using HALL sensors
#   Author: SOLOMOTORCONTROLLERS
#   Date: 2021
#   Code version: 1.0.0
#   Availability: https://github.com/Solo-FL/SOLO-motor-controllers-PYTHON-RASPBERRY-PI-library/
#   Please make sure you are applying the right wiring between SOLO and your RASPBERRY-PI
#   The Code below has been tested on RASPBERRY-PI 4B
#   The Motor used for Testings: DB56C036030-A
# _________________________________________________________________________________________________

# Importing PYTHON RASPBERRY-PI library
import solo_motor_controller as solo
import time
import sys
sys.path.append("../src")


# the device address of SOLO
__solo_address = 0

# For this Test, make sure you have calibrated your HALL sensors before
# to know more please read: https: // www.solomotorcontrollers.com/hall-sensors-to-solo-for-controlling-speed-torque-brushless-motor/

# In this example, make sure you put SOLO into Closed-Loop by
# pressing the Piano Switch NO  # 5 DOWN. in SOLO UNO

# The Piano Switch Setup on SOLO UNO are as below
#  PIN 5 Down: closed-loop
#  PIN 3 UP(Not in DFU mode)

# ____________________________________________________________________
# High Speed High Performance Baudrate (Recommended)
# Use this baudrate to have the best and real performance
# of SOLO under all conditions 937500;
baudrate = 937500

# Low Speed Low Performance Baudrate
# Use this baudrate only for devices that don't support
# 937500 or 921600 baudrates.
#baudrate = 115200
# _____________________________________________________________________

# Desired Switching or PWM Frequency at Output in kHz
pwm_frequency = 22

# Motor's Number of Poles
numberOfPoles = 8

# Select the Normal BLDC_PMSM motor type
motor_type = 1

# Current Limit of the Motor
current_limit = 12.5

# Define Desired Torque referrrence
desired_torque_iq = 0.0

# Define Desired Speed referrrence
desired_motor_speed = 0

# Battery or Bus Voltage
bus_voltage = 0

# Motor speed feedback
actual_motor_speed = 0

# Motor Iq(torque) feedback
actual_motor_torque_iq = 0.0


def __loop():

    # set the Direction on C.W.
    __solo_driver.set_direction(0)
    
    #set desired Iq ( torque ) in Amps
    desired_torque_iq = 2.258
    __solo_driver.set_torque_reference(desired_torque_iq)

    # wait till motor reaches to the reference
    time.sleep(1)

    actual_motor_torque_iq = __solo_driver.get_quadrature_current()
    print("\n Actual Motor Iq: \n", actual_motor_torque_iq)
    
    actual_motor_speed = __solo_driver.get_speed()
    print("\n Motor Speed: \n", actual_motor_speed)
    
    # wait 
    time.sleep(3)
    
    # stop the motor
    desired_torque_iq = 0.0
    __solo_driver.set_torque_reference(desired_torque_iq)
    time.sleep(1)
    
    actual_motor_torque_iq = __solo_driver.get_quadrature_current()
    print("\n Actual Motor Iq: \n", actual_motor_torque_iq)
    
    actual_motor_speed = __solo_driver.get_speed()
    print("\n Motor Speed: \n", actual_motor_speed)
    
    # set the Direction on C.C.W.
    __solo_driver.set_direction(1)
    
    #set desired Iq ( torque ) in Amps
    desired_torque_iq = 3.512
    __solo_driver.set_torque_reference(desired_torque_iq)

    # wait till motor reaches to the reference
    time.sleep(1)

    actual_motor_torque_iq = __solo_driver.get_quadrature_current()
    print("\n Actual Motor Iq: \n", actual_motor_torque_iq)
    
    actual_motor_speed = __solo_driver.get_speed()
    print("\n Motor Speed: \n", actual_motor_speed)
    
    # wait 
    time.sleep(3)

    # stop the motor
    desired_torque_iq = 0.0
    __solo_driver.set_torque_reference(desired_torque_iq)
    time.sleep(1)
    
    actual_motor_torque_iq = __solo_driver.get_quadrature_current()
    print("\n Actual Motor Iq: \n", actual_motor_torque_iq)
    
    actual_motor_speed = __solo_driver.get_speed()
    print("\n Motor Speed: \n", actual_motor_speed)
    
    # wait 
    time.sleep(3)


def __setup():
    # Initialize the SOLO object using the device address of SOLO at 0
    global __solo_driver
    __solo_driver = solo.SoloMotorController(__solo_address, baudrate)

    time.sleep(2)

    bus_voltage = __solo_driver.get_bus_voltage()
    while bus_voltage <= 0:
        # wait here till communication is established
        bus_voltage = __solo_driver.get_bus_voltage()
        print("\n Trying to Connect To SOLO")
        time.sleep(1)

    print("\n Communication Established succuessfully!")

    # Initial Configurations
    __solo_driver.set_pwm_frequency(pwm_frequency)
    __solo_driver.set_current_limit(current_limit)

    # select Digital Mode
    __solo_driver.set_command_mode(1)

    __solo_driver.set_motor_type(motor_type)

    # run the motor identification
    # run ID. always after selecting the Motor Type!
    # Torque Controller Gains are tuned after Identification automatically
    __solo_driver.set_identification(1)

    print("\n Identifying the Motor")

    # wait at least for 2sec till ID. is done
    time.sleep(3)

    # Operate in Hall Sensor Mode
    __solo_driver.set_speed_control_mode(2)

    # Control The Torque
    __solo_driver.set_control_mode(1)

    # Set the Number of Poles 
    __solo_driver.set_number_of_poles(numberOfPoles)
    

    while True:
        __loop()


def do_work():
    __setup()


if __name__ == "__main__":
    do_work()

In our tests for this tutorial, to be able to see the Torque Step responses, we just locked the shaft of the BLDC like the image below and made sure the shaft doesn’t move at all, so in that case, we could see the step response of the requested Iq ( Torques) sent from Raspberry Pi

1 Like