0

I am unable to understand parts of the code

#!/usr/bin/python3
# File name   : motor.py
# Description : Control Motors 
# Website     : www.adeept.com
# E-mail      : support@adeept.com
# Author      : William
# Date        : 2018/10/12

import RPi.GPIO as GPIO
import time
# motor_EN_A: Pin7  |  motor_EN_B: Pin11
# motor_A:  Pin8,Pin10    |  motor_B: Pin13,Pin12

Motor_A_EN    = 4
Motor_B_EN    = 17

Motor_A_Pin1  = 14
Motor_A_Pin2  = 15
Motor_B_Pin1  = 27
Motor_B_Pin2  = 18

Dir_forward   = 0
Dir_backward  = 1

pwm_A = 0
pwm_B = 0

def setup():#Motor initialization
    global pwm_A, pwm_B
    GPIO.setwarnings(False)
    GPIO.setmode(GPIO.BCM)
    GPIO.setup(Motor_A_EN, GPIO.OUT)
    GPIO.setup(Motor_B_EN, GPIO.OUT)
    GPIO.setup(Motor_A_Pin1, GPIO.OUT)
    GPIO.setup(Motor_A_Pin2, GPIO.OUT)
    GPIO.setup(Motor_B_Pin1, GPIO.OUT)
    GPIO.setup(Motor_B_Pin2, GPIO.OUT)
    try:
        pwm_A = GPIO.PWM(Motor_A_EN, 1000)
        pwm_B = GPIO.PWM(Motor_B_EN, 1000)
    except:
        pass

def motorStop():#Motor stops
    GPIO.output(Motor_A_Pin1, GPIO.LOW)
    GPIO.output(Motor_A_Pin2, GPIO.LOW)
    GPIO.output(Motor_B_Pin1, GPIO.LOW)
    GPIO.output(Motor_B_Pin2, GPIO.LOW)
    GPIO.output(Motor_A_EN, GPIO.LOW)
    GPIO.output(Motor_B_EN, GPIO.LOW)

def motor_right(status, direction, speed):#Motor 2 positive and negative rotation
    global  pwm_B
    if status == 0: # stop
        motorStop()
    else:
        if direction == Dir_forward:
            GPIO.output(Motor_B_Pin1, GPIO.HIGH)
            GPIO.output(Motor_B_Pin2, GPIO.LOW)
            pwm_B.start(100)
            pwm_B.ChangeDutyCycle(speed)
        elif direction == Dir_backward:
            GPIO.output(Motor_B_Pin1, GPIO.LOW)
            GPIO.output(Motor_B_Pin2, GPIO.HIGH)
            pwm_B.start(0)
            pwm_B.ChangeDutyCycle(speed)

def motor_left(status, direction, speed):#Motor 1 positive and negative rotation
    global pwm_A
    if status == 0: # stop
        motorStop()
    else:
        if direction == Dir_forward:#
            GPIO.output(Motor_A_Pin1, GPIO.HIGH)
            GPIO.output(Motor_A_Pin2, GPIO.LOW)
            pwm_A.start(100)
            pwm_A.ChangeDutyCycle(speed)
        elif direction == Dir_backward:
            GPIO.output(Motor_A_Pin1, GPIO.LOW)
            GPIO.output(Motor_A_Pin2, GPIO.HIGH)
            pwm_A.start(0)
            pwm_A.ChangeDutyCycle(speed)
    return direction


def destroy():
    motorStop()
    GPIO.cleanup()             # Release resource


try:
    pass
except KeyboardInterrupt:
    destroy()

Here is the link to the entire project, please check this:

What is the meaning of the lines :

  • pwm_A = GPIO.PWM(Motor_A_EN, 1000)
  • pwm_B = GPIO.PWM(Motor_B_EN, 1000)

        def motor_left(status, direction, speed):#Motor 1 positive and negative rotation
            global pwm_A
            if status == 0: # stop
                motorStop()
            else:
                if direction == Dir_forward:#
                    GPIO.output(Motor_A_Pin1, GPIO.HIGH)
                    GPIO.output(Motor_A_Pin2, GPIO.LOW)
                    pwm_A.start(100)
                    pwm_A.ChangeDutyCycle(speed)
                elif direction == Dir_backward:
                    GPIO.output(Motor_A_Pin1, GPIO.LOW)
                    GPIO.output(Motor_A_Pin2, GPIO.HIGH)
                    pwm_A.start(0)
                    pwm_A.ChangeDutyCycle(speed)
            return direction
    

What is the meaning of status, direction, speed in the function declaration?

Also pwm.changeDutyCycle(speed), What is the speed?

tlfong01
  • 4,384
  • 3
  • 9
  • 23
Vaibhav
  • 51
  • 1
  • 6
  • Ah, If I remember correctly, you Adeept AI Mars Rover is using the L298N DC motor driver. To move forward, backward, stop, you just use GPIO pin in output mode to control the L298N. But if you wish to change speed, you need to use GPIO pin in PWM mode. In short, output mode for newbies, PWM mode for ninjas. The first reference below is for newbies, rest for ninjas: (1) https://www.aliexpress.com/i/32676329352.html (2) https://raspberrypi.stackexchange.com/questions/104365/rpi4b-can-control-either-one-of-two-l298n-modules-each-driving-two-motors-but, / to continue, ... – tlfong01 Mar 01 '20 at 10:05
  • (3) https://raspberrypi.stackexchange.com/questions/99460/rpi-gpiozero-l298n-dc-motor-driver-problem (4) https://raspberrypi.stackexchange.com/questions/98513/program-my-robot-with-python (5) https://raspberrypi.stackexchange.com/questions/96515/why-dont-my-motors-rotate (6) https://raspberrypi.stackexchange.com/questions/96258/how-can-rpi-python-control-motor-drivers-l293d-or-l298n/96332#96332 (7) https://raspberrypi.stackexchange.com/questions/95999/why-isn-t-my-raspberry-pi-motor-spinning, Happy reading. Cheers. – tlfong01 Mar 01 '20 at 10:06
  • You have asked 3 Questions asking us to explain someone's code. This is not the way this site works. Take the [Tour](https://raspberrypi.stackexchange.com/tour) – Milliways Mar 01 '20 at 10:29
  • @tlfong01 Thanks, sir – Vaibhav Mar 01 '20 at 11:57
  • @Vaibhav, you are welcome. So your Rpi school project report deadline is tomorrow? No wonder you are a little bit impatient. Add oil and burn your midnight oil. :) – tlfong01 Mar 01 '20 at 12:48
  • And the two references on L298N in my very first answer to your Mars Rover question should be helpful to understand L298N operation. – tlfong01 Mar 03 '20 at 11:30
  • Now to keep you, the impatient guy happy, I will go fast, doing four things in one go: (1) speed, (2) frequency, (3) PWM, and (4) duty cycle. You need to understand as describel in my other answer, how to flip two switch to turn the motor clockwise and counter clockwise. – tlfong01 Mar 05 '20 at 13:51

1 Answers1

1

Answer

Part 1 - Over simplified explanation of the L298N Dual Bridge Motor Driver

Now let us first look at the picture below.


pwm etc


(1.1) Suppose the switches SW1 and Sw2 are in their positions as shown. The electric current will flow from +12V, following the little pink arrows, passing through the coil, I mean the motor coil, and the motor will turn happily non stop.

(1.2) Now if you flip SW1 to left, and keep SW2 stay in its current position, then +12V has no way (circuit) to pass current, and no current in coil, so the motor stops.

(1.3) Now if you repeatedly flip SW1 to right for one second, then left for one second, then right, then left, ... Then you will find motor turns for one second, then stops for one seconds, and so on.

(1.4) So in one minute, you are doing left, right, left, right, ... ie, you are repeating the two second action 30 times per minute. The scientists call this how many times per minute or per seconds "FREQUENCY".

Frequency can be very high, eg 1,000 times (cycles) per second, which has a special name called "Hertz" or "Hz". And like the unit metre, you can have km for kilo-meter, same for kHz, MHz etc.

(1.5) Now what is duty cycle? Suppose you flip SW1 to left for one second, then right for three seconds, then the percentage of current on, or motor moving is 1 second / (1 + 3) seconds = 1/4 = 25%. Then we say 20% DUTY CYCLE. duty cycle

(1.6) Now what about speed? If you use a stop watch to count how many motor "turns" or "revolutions" are there in one minute, then that is "SPEED", say 3,600 revolutions per minute or 3,600 rpm.

(1.7) Now finally, PWM, which means Pulse Width Modulation. I would suggest you to ask Lady Ada of AdaFruit (See Ref 2 below), because I don't know how to explain PWM using my broken English.


Part 2 - Understanding the python code to move motor change speed

In Part 1, we explained how to flip SW1 to pass current 25% of the time (duty cycle = 25%). We can also using other duty cycle, say 50%, to turn the motor clockwise faster. By the same token, to turn motor counter clockwise and change speed, we change the duty cycle of SW2. In the real L298N, the lazy EE guys do not change the duty cycle of SW1 and SW2 separately. Instead, they use a "main" switch called "Enable" switch, to enable or disable both switches SW1 and SW2 AT THE SAME TIME, as illustrated below.

pwm speed control

l298n pwm mode pin

Referring to the schematic above,

(1) SW1, SW2 (actually In1, In2, connected to two Rpi GPIO pins in output mode) are used to turn motor A clockwise or counter clockwise.

(2) Enable switch (actually EnA, connected to one GPIO pin in PWM mode) is used to change speed of motor A by changing the duty cycle of enabling the SW1. SW2 at the same time.

The full listing of the Mars Rover's real code motor.py is given in Appendix A below. I might later, sprinkle a couple of comments to make the code more newbie friendly to read and understand. The OP, if impatient to wait, can DIY figuring out how the code works.


Part 3 - Understanding the python code to turn servo using AdaFruit PCA9685 PWM Controller Library]

My answer is coming to end. The OP should now have a rough idea of how to use the Rpi's four GPIO pins in output mode and two GPIO pins in PWM mode to change direction and speed of the Mars Rover.

The OP also asks about the turn.py code which is different from the motor.py code explained here. What causes confusion is the both codes use PWM: motor.py using GPIO pins in PMW mode, turn.py, on the other hand, uses the AdaFruit PCA968 PWM controller library to turn the three servos (car direction, supersonic sensor, and Rpi camera).

Adeept Mars Rober turn.py [Using AdaFruit PCM9685 PWM Controller Library]

The code turn.py is simple and easy to understand, because all the complex code of PCM9685 is hidden in the library functions which is off topic, therefore not touched here..


References

(1) PWM (Pulse Width Modulation) - Wikipedia

(2) Adafruit PCA9685 16-Channel PWM / Servo Controller Tutorial - Lady Ada

(3) Hertz -Wikipedia

(4) Heinrich Hertz - Wikipedia

Appendices

Appendix A - Motor.py to control speed of left and right motors, using two GPIO pins as PWM pins

# File name   : motor.py
# https://github.com/adeept/Adeept_PiCar-B/blob/master/server/motor.py

#!/usr/bin/python3
# File name   : motor.py
# Description : Control Motors 
# Website     : www.adeept.com
# E-mail      : support@adeept.com
# Author      : William
# Date        : 2018/10/12

import RPi.GPIO as GPIO
import time

# motor_EN_A: Pin7         |  motor_EN_B: Pin11
# motor_A:  Pin8, Pin10    |  motor_B: Pin13, Pin12

Motor_A_EN    = 4
Motor_B_EN    = 17

Motor_A_Pin1  = 14
Motor_A_Pin2  = 15
Motor_B_Pin1  = 27
Motor_B_Pin2  = 18

Dir_forward   = 0
Dir_backward  = 1

pwm_A = 0
pwm_B = 0

def setup():#Motor initialization
    global pwm_A, pwm_B
    GPIO.setwarnings(False)
    GPIO.setmode(GPIO.BCM)
    GPIO.setup(Motor_A_EN, GPIO.OUT)
    GPIO.setup(Motor_B_EN, GPIO.OUT)
    GPIO.setup(Motor_A_Pin1, GPIO.OUT)
    GPIO.setup(Motor_A_Pin2, GPIO.OUT)
    GPIO.setup(Motor_B_Pin1, GPIO.OUT)
    GPIO.setup(Motor_B_Pin2, GPIO.OUT)
    try:
        pwm_A = GPIO.PWM(Motor_A_EN, 1000)
        pwm_B = GPIO.PWM(Motor_B_EN, 1000)
    except:
        pass

def motorStop():#Motor stops
    GPIO.output(Motor_A_Pin1, GPIO.LOW)
    GPIO.output(Motor_A_Pin2, GPIO.LOW)
    GPIO.output(Motor_B_Pin1, GPIO.LOW)
    GPIO.output(Motor_B_Pin2, GPIO.LOW)
    GPIO.output(Motor_A_EN, GPIO.LOW)
    GPIO.output(Motor_B_EN, GPIO.LOW)

def motor_right(status, direction, speed):#Motor 2 positive and negative rotation
    global  pwm_B
    if status == 0: # stop
        motorStop()
    else:
        if direction == Dir_forward:
            GPIO.output(Motor_B_Pin1, GPIO.HIGH)
            GPIO.output(Motor_B_Pin2, GPIO.LOW)
            pwm_B.start(100)
            pwm_B.ChangeDutyCycle(speed)
        elif direction == Dir_backward:
            GPIO.output(Motor_B_Pin1, GPIO.LOW)
            GPIO.output(Motor_B_Pin2, GPIO.HIGH)
            pwm_B.start(0)
            pwm_B.ChangeDutyCycle(speed)

def motor_left(status, direction, speed):# Motor 1 positive and negative rotation
    global pwm_A
    if status == 0: # stop
        motorStop()
    else:
        if direction == Dir_forward:#
            GPIO.output(Motor_A_Pin1, GPIO.HIGH)
            GPIO.output(Motor_A_Pin2, GPIO.LOW)
            pwm_A.start(100)
            pwm_A.ChangeDutyCycle(speed)
        elif direction == Dir_backward:
            GPIO.output(Motor_A_Pin1, GPIO.LOW)
            GPIO.output(Motor_A_Pin2, GPIO.HIGH)
            pwm_A.start(0)
            pwm_A.ChangeDutyCycle(speed)
    return direction


def destroy():
    motorStop()
    GPIO.cleanup()             # Release resource


try:
    pass
except KeyboardInterrupt:
    destroy()

tlfong01
  • 4,384
  • 3
  • 9
  • 23