Motor Lab

Materials

In this laboratory we will use the Motor Hat developed by Adafruit: https://www.adafruit.com/products/2348 which has a detailed tutorial https://learn.adafruit.com/adafruit-dc-and-stepper-motor-hat-for-raspberry-pi 

The main components of the hat are power electronics to drive currents into motors and an integrated circuit to create pulses. The motor driver   (TB6612) takes up to 15V and can deliver 1.2A of current and can control two DC motors with an H-bridge. There are two motor drivers on the hat resulting in up to 4 DC motors or 2 bipolar stepper motors. The PWM driver  (PCA9685) creates precise pulses to control the speed of DC motors or the rotation of stepper motors or the orientation of a servo motor. The Raspberry Pi could create such pulses on the digital output pins but depending on the CPU usage from other applications, the pulse precision varies. A dedicated chip guarantees precise timing.  The Raspberry Pi communicates to the PWM driver with I2C. 12 channels of the PWM driver are used to create signals for the motor drivers and 4 channels are available to control servo motors (0,1,14,15).

We have two types of motor hats. One operates at i2c address 0x60 the other 0x6F/0x70. 

Sometimes the Adafruit Motor hats are out of stock and the clones on AliExpress will take 2 weeks to ship. If you short the motor hat, it might become difficult to complete the lab on time.

Assembly and Installation of Motorhat

Make sure you covered exposed wires on the back of the Motorhat with electrical tape.

If the extension header pins are bent, use pliers and carefully bend them back. Ask for instructor help if needed.

Do not power up the Raspberry Pi with the Motor Hat installed without having the standoff screws in place!

Make sure power wires are all the way in the screw in terminal so that they can not short. Cut them to appropriate length.

Likely your Motorhat is already assembled, so you can skip the followng section below.

The motor-hat does not have its connectors attached. We will need to attach the 40 pin connector to the Raspberry Pi, the screw in terminals and pins for 5V, GND, and the PWM outputs. It is critical that you solder those pins onto the chip precisely and do not use too much solder, otherwise you will not be able to connect other parts to the pins.

Do NOT use the provided 40 pin connector. Use the custom 40 pin connector that allows you to stack a second hat onto the motor-hat. It is very tedious to de-solder 40 pins if you used the wrong connector. If you mount the parts incorrectly, I will ask you to order a replacement hat.  Based on pictures on the Adafruit website it should be pretty clear which side of the board points upwards and which connector goes where.

There are also standoffs that have the correct length to attach the board properly to the Raspberry Pi. 

The pins can NOT have solder on them along at least the top 2/3 of the pin. When you make the solder connections do the following:

You will also need to place 4 pins to the PWM output 0,1,14,15 and 4 times 3 pins to the 5V, GND and 3V lines as well as the screw in terminals. 

The screw in terminals come in 3 connector and 2 connector types. In order to create a 5 pin screw in terminal you need to slide a 2 pin and a 3 pin terminal into each other. It will take a close look to figure out how the plastic housings can be mated.

Software

To install the motor library use the following commands. Like for the humidity and pressure sensor, this library depends on Adafruit GPIO and Adafruit simpleIO library which should already be installed. There is newer blinka compatible driver but that driver does not support the servo motors.

# Activate your environment

cd ~/pythonBME210

source env/bin/activate

# You might have the wrong board version installed

pip3 uninstall board

# Install the modules -------------------------------------------

pip3 install adafruit-circuitpython-typing

# Make sure Blinka is latest version

pip3 install --upgrade --force-reinstall Adafruit-Blinka

# Get the motor modules

pip3 install adafruit-circuitpython-pca9685

pip3 install adafruit-circuitpython-motor

pip3 install adafruit-circuitpython-motorkit

# Get a copy of the example programs

git clone https://github.com/adafruit/Adafruit_CircuitPython_Motor

git clone https://github.com/adafruit/Adafruit_CircuitPython_PCA9685

git clone https://github.com/adafruit/Adafruit_CircuitPython_MotorKit

git clone https://github.com/uutzinger/meArmPi.git

And please note that your Motor Hat might have different address. You can find it using:

sudo i2cdetect -y 1

Servo Motor Setup

Do not power up the Raspberry Pi with the Motor Hat installed without having the standoff screws in place!

Make sure power wires are all the way in the screw in terminal so that they can not short. Strip them to appropriate length.

How does Servo Motor work?: https://www.sparkfun.com/servos 

Connections:

+ you will need to connect your Power Supply red connector to the power input of the motor-hat. 

- you will need to connect your Power Supply black connector to the power input of the motor-hat. 

Use black and red stranded wire and connect it to the power input of the motor-hat. Set the programmable power supply in the lab to 5V and verify that it provides 5V between the red and the black banana connectors. Connect the wires from the motor-hat to the output of the power supply using the screw terminals and the power supplies screw on covers of the banana connectors.

Take the motor wires and connect them to the to a PWM servo port . On the servo motor, GND is black/brown, 5V is red and the PWM signal goes into the white/yellow signal cable. Verify that the motor is connected properly.

Software

Please check the examples in https://github.com/adafruit/Adafruit_CircuitPython_Motor/tree/main/examples. We have the PCA9685 Pulse Generator. The channels 0, 1, 14 and 15 are available to control Servos. The examples use channel 7 which is not available to us.

The PWM frequency should be at 50Hz (20milli seconds).

A good minimum pulse is 500 and good max is 2500 micro seconds. Those are the end positions of the motor axle. 

The simplest code likely looks like this (let staff know if this does not work):

import time

from board import SCL, SDA

import busio

from adafruit_pca9685 import PCA9685

from adafruit_motor import servo

i2c = busio.I2C(SCL, SDA)

pca = PCA9685(i2c, address=0x40)

pca.frequency = 50

servo0 = servo.Servo(pca.channels[0], min_pulse=580, max_pulse=2350)

for i in range(180):

    servo0.angle = i

    time.sleep(0.03)

for i in range(180):

    servo0.angle = 180 - i

    time.sleep(0.03)

pca.deinit()

Stepper Motor Setup

Do not power up the Raspberry Pi with the Motor Hat installed without having the standoff screws in place!

Make sure power wires are all the way in the screw in terminal so that they can not short. Strip them to appropriate length.

Make sure the motor wires are all the way in the screw in terminal so that they can not short. Strip them to appropriate length.

Remove the Servo Motor from the Motor Hat. You can not run both Motors on the same hat.

How does a Stepper Motor work: 

https://en.wikipedia.org/wiki/Stepper_motor 

Hook up:

We have a bi-polar stepper motors that run at up to 10V but will also run at 5V. It has 200 steps per revolution (instructor will need to verify). The NEMA17 StepperOnline P/N 17HS15-1504S motor has two coils. 

Black, goes to motor 1 (M1) on the hat 

Green, goes to motor 1 (M1) on the hat

Blue, goes to motor 2 (M2) on the hat

Red, goes to motor 2 (M2) on the hat

M3 and M4 would work also. Do not connect to the middle GND terminal. To attach the motor you can use male-male jumper cables. To make sure the cables don't fall out of the connector, you can keep them in place with tape.

Software: 

Stepper Motor test code is at https://github.com/adafruit/Adafruit_CircuitPython_MotorKit in the examples folder.

DC Motor

Do not power up the Raspberry Pi with the Motor Hat installed without having the standoff screws in place!

Make sure power wires are all the way in the screw in terminal so that they can not short. Strip them to appropriate length.

Make sure the motore wires all all the way in the screw in terminal so that they can not sort. Strip them to appropriate length.

Remove Servo Motor from the Motor Hat. You can not run both Motors on the same hat.

How does DC Motor work:

https://en.wikipedia.org/wiki/DC_motor 

Hook up guide:

The raspberry pi pinout can be seen by running the command pinout in the terminal or in this image: https://cdn.sparkfun.com/assets/learn_tutorials/4/2/4/header_pinout.jpg 

DO NOT JUST PLUG IN SOMEWHERE, MAKE AN EDUCATED CHOICE.

DO NOT COPY YOUR NEIGHBOR's SETUP.  (you dont learn anything and you might fry two motor encoders)

The micro DC Motor is a 6V motor with an attached transmission and free running at 75 rotations per minute (RPM).  It has a two Hall rotation encoders giving 7 pulsed per motor rotation and xx? pulses per shaft rotation. 

You will need to solder jumper wires onto the cable that is attached to the motor. Use shrink tubing to cover the solder joint.

We will power the encoder with 3.3 V from Raspberry Pi (black wire) and read the yellow and green wire with an input pin (e.g. pin 40 which is GPIO21). Ground could be pin 39 on the other side of pin 40 (blue). Any input pin will work for signal input except the I2C and SPI pins. You need to check the pinout diagram of the raspberry pi above.  Dimensions and connections are shown here: https://www.aliexpress.us/item/3256804813215103.html?spm=a2g0o.order_list.order_list_main.29.46e718023Fx0c3&gatewayAdapt=glo2usa 

[Not used] The short DC Motor is a 6-12V motor with an attached transmission 1:110,  free running at 64 rotations per minute (RPM).  It has a single Hall rotation encoder giving one pulse per motor rotation and 110 pulses per shaft revolution. The power to the motor is connected to the orange and blue wire. The encoder receives its 3.3V on the red wire and ground on the black wire. The position signal is provided on the white wire. We will power the encoder with 3.3 V from Raspberry Pi (pin 1) and read the white wire with an input pin (e.g. pin 40 which  is GPIO21). Ground could be pin 39 on the other side of pin 40. Any input pin will work for signal input  except I2C and SPI pins. You need to check the pinout diagram of the raspberry pi above.  Dimensions and connections are shown here: https://www.aliexpress.com/item/33008547634.html?spm=a2g0s.9042311.0.0.3dfa4c4dtX3HRJ

Image below on the right is for short DC motor with encoder.

[Not used] The longer DC Motor is JGA25-370 that runs at 6-12V input with an attached transmission 1:20.4, free running at 190 (6V) up to 350 (12) RPM.  It has a quadrature position encoder giving 11 pulses per revolution and on the output shaft 224.4 pulses per revolution. The wiring differs on some of the encoders. We have the red colored circuit board attached to the motor. There  the power to the motor is connected to the outermost wires (white and red) and need to be connected to M3. Black and Blue are power to encoder electronics and require 3.3V on blue and black being GND. Yellow and Green are the pulses indicating a rotation.  Its possible to determine forward backward rotation by comparing the pulses on yellow and green.  An other version of this motor (green PCB) uses this encoder design: https://sc01.alicdn.com/kf/HTB1e6dRGpXXXXctaXXXq6xXFXXX3/200666655/HTB1e6dRGpXXXXctaXXXq6xXFXXX3.jpg.  

Encoder:

The first encoder Image below in the middle is for long DC motor with encoder.

The second image below is for the micro DC motor encoder.

Connect one of the encoder signals to a raspberry pi input pin. Any input pin except I2C and SPI will work. You need to check the raspberry pi pinout to make sure you hook up the encoder signal and power 3.3V and GND to the right pins on the raspberry pi header. Do NOT connect to 5V and do  not connect the encoder output to 5V or GND please.

Software:

Some example code to count the pulses is below. You will need to turn the motor by hand to observe that the counts increasing. If this does not work, check with staff.

The speed of the motor is counts per second. I believe you will receive 7 pulses for one rotation.

The motor examples from  adafruit-circuitpython-motorkit should be used to complete this code. The other examples are not specifically made for the motor hat.

Make a graph that shows the speed (rotations per second) of the motor versus the motor "power" value. You can adjust the pulse width of the motor to change the power going into the motor. 100% is always on. 50% is half the time on.

Consider writing a loop with power changing from 0 to 255.  Each iteration in your loop you should give the motor some time to run otherwise the counter will not increment. Your motor will continue running if you are not releasing it, so perhaps at the end of the loop you will set speed to 0 or turn off the motor.

# Setup

##########################################


import RPi.GPIO as GPIO # what is this for?

import time

# you need to import motor related functions

from Ada ...


# Counter Service Routine

##########################################

# Independent piece of code that is run when event occurs.

# Main program stops, and this is executed and then the 

#   computer goes back to the main program

def myCallback(pin):

   global counter

   counter+=1


# Counter Setup

##########################################

encoderPin = 21 # this is the number of GPIO pin, e.g. GPIO21 is located on pin 40

counter = 0


GPIO.setmode(GPIO.BCM) # this depends on type or raspberry pi

GPIO.setup(encoderPin, GPIO.IN, pull_up_down=GPIO.PUD_UP) # why  do we need pullup?


#  setup the pin to count and attach the callback function to this pin

GPIO.add_event_detect(encoderPin, GPIO.RISING, callback=myCallback)


# Motor Setup

##########################################

# Motor setup here

#

# Check in https://github.com/adafruit/Adafruit_CircuitPython_MotorKit

# for the DC motor example code.

#

# This section you will need to implement for your final code.

# You do not need to write this code just for testing the encoder as

# you can run this code without the motor and turn the axle by hand

# to test the encoder.

#

# 1) Motor Power/Speed/Throttle statement

# 2) Release statement

# 3) Direction statement


# CSV file setup

##########################################

# you want to create a file into which you will write the data


# Main Program

##########################################

# if you are just testing the encoder:

while True:

# for the final program you will want to use:

# for power in range(0,255,5):


    # set motor power Here, Do not exceed 255. You will want to loop through values. 

    # motor power command goes here

    time.sleep(0.5) # how long do you think it takes until the motor has reached the new speed?

    

  #Let motor spin at set power and measure counts.

    previousCounter = counter

    previousTime = time.time()

    time.sleep(1)

    currentCounter = counter
    currentTime = time.time()

    # The next line will not work unless you provide the correct variables

    # delta X is the change of motor position since last time

    # delta T is the time between now and the last time

    print("Speed: %f" %(delta-x/delta-t) ) 

    # Now you will want to write into the CSV file


# stop the motor and close the motor object

Troubleshooting

It is possible that the motor hat becomes unresponsive. The python library will open up correctly and i2cdetect command shows that its connected, but the motors do not work.

This will require powering down the motor hat and booting it up again (unplug external power supply). It might also require that you power down (shutdown and unplug) the raspberry pi.

You should be able to test the motor hat by running the servo motor program you made as those motors take least amount of effort to connect.

Writing CSV File

If you want to import your data into Excel you should save it in a "comma separated value" file.

Please read csv documentation of python: https://docs.python.org/3/library/csv.html

This line in the document sounds really good to me: "The corresponding simplest possible writing example is: " .....

Then the question is what is an iterable? Examples are lists or combining the two variables setspedd and measuredspeed into a list like: setspeed, measuredspeed]. 

Likely writerow expects the iterable to be a string. You can convert to string using "{}".format(value)  you can set the format precision with {:.2f}

Please repalce

with open('some.csv', 'w', newline='') as f:

   writer = csv.writer(f)

with 

f = open('some.csv', 'w', newline='')

writer = csv.writer(f)

and place it outside the loop so that the file does not need to be opened each time you want to write to it. Then you would need to close the file after you finished with the loop with

f.close()

otherwise some of the data will not be written to the file and it might be incomplete or empty.

When you use the with statement, it automatically closes the file when with is finished. When you close the file and want to add data you will want to open the file using 'a' for append instead of 'w' which stands for write. If you write to the file with having file opened outside the loop, you would not need to append as the file remains open until the loop is completed. 

Turn In

Please show the DC Motor, Servo and Stepper motors working. They can not run at the same time, so you will need to show the TA, ULAs or instructors each time. 

Collect DC motor data by measuring the pulses per second at a variety of power settings (From 0 to 255 or in the newer library from 0 to 1 (=100%)). Please create a simple graph of the set power/speed vs measured speed (include axis labels and title, units etc.). 

This requires you to use example software from https://github.com/adafruit/Adafruit_CircuitPython_MotorKit and the code example above to modify it with the call back routine for counting the encoding pulses. The key element for a call back that simply counts the pulses is above. Pin is the pin on the raspberry you used to count the pulses.

To summarize, you will need to develop a code using the example code above as well as the example code on Github. This code needs to set the power/speed/throttle of the DC motor and also mathematically calculate the speed at which the motor is actually rotating. This code will increment the power/speed/throttle from 0 to 255 (or 1) and accompanying measured speeds will be calculated at each set speed.

When you set the power/speed/throttle it will take the motor some time to speed up. So wait a little bit before you measure the speed.

Each of these data points need to be added to a new line in a csv file to store the data and graph it for the report. The final graph should look similar to this with axis labels, units, a trendline, and an equation included as well.  

Use this report outline for your lab submission. Answer the questions and put in the graphs/screenshots.