stianeikeland / go-rpio

:electric_plug: Raspberry Pi GPIO library for go-lang
MIT License
2.18k stars 221 forks source link

How would I translate this Python PWM code to go with go-rpio? #48

Open kramer65 opened 4 years ago

kramer65 commented 4 years ago

I'm trying to convert some working Python code to run in go. The Python is as follows:

import RPi.GPIO as GPIO
import time

servoPIN = 13
GPIO.setmode(GPIO.BCM)
GPIO.setup(servoPIN, GPIO.OUT)

p = GPIO.PWM(servoPIN, 50) # GPIO 13 for PWM with 50Hz
p.start(2.5) # Initialization
try:
  while True:
    p.ChangeDutyCycle(5)
    time.sleep(0.5)
    p.ChangeDutyCycle(7.5)
    time.sleep(0.5)
    p.ChangeDutyCycle(10)
    time.sleep(0.5)
    p.ChangeDutyCycle(12.5)
    time.sleep(0.5)
    p.ChangeDutyCycle(10)
    time.sleep(0.5)
    p.ChangeDutyCycle(7.5)
    time.sleep(0.5)
    p.ChangeDutyCycle(5)
    time.sleep(0.5)
    p.ChangeDutyCycle(2.5)
    time.sleep(0.5)
except KeyboardInterrupt:
  p.stop()
  GPIO.cleanup()

This Python code works. The servo moves constantly.

So I tried translating the code to Go using go-rpio. I got to this:

package main

import (
    "fmt"
    rpio "github.com/stianeikeland/go-rpio"
    "time"
)
const PWM_PIN_NUMBER = 13

func main() {
    err := rpio.Open()
    if err != nil {
        panic("Opening the pin goes wrong")
    }

    defer rpio.Close()

    pin := rpio.Pin(PWM_PIN_NUMBER)
    fmt.Println(pin)
    pin.Mode(rpio.Pwm)
    pin.Freq(50)
    pin.DutyCycle(0, 50)

    for {
        fmt.Println(5)
        pin.DutyCycle(uint32(5), 50)
        time.Sleep(1 * time.Second)

        fmt.Println(7)
        pin.DutyCycle(uint32(7), 50)
        time.Sleep(1 * time.Second)

        fmt.Println(10)
        pin.DutyCycle(uint32(10), 50)
        time.Sleep(1 * time.Second)

        fmt.Println(12)
        pin.DutyCycle(uint32(12), 50)
        time.Sleep(1 * time.Second)

        fmt.Println(10)
        pin.DutyCycle(uint32(10), 50)
        time.Sleep(1 * time.Second)
    }
}

The code runs, but the servo doesn't move at all.

Does anybody know what I'm doing wrong here?

drahoslove commented 4 years ago

Hi, in PWM mode the freq method does not set the output frequency, but the base clock frequency of the channel. You have to multiply it by the cycle length (because the output frequency is given by base clock frequency divided by cycle length as it is written in the doc). This should work:

    pin.Mode(rpio.Pwm)
    pin.Freq(50 * 50)
    pin.DutyCycle(0, 50)
...
        pin.DutyCycle(7, 50)

or this:

    pin.Mode(rpio.Pwm)
    pin.Freq(50 * 100)
    pin.DutyCycle(0, 100)
...
        pin.DutyCycle(15, 100) // this will give you the 7.5/50 ratio you have in your python code
shanghuiyang commented 4 years ago

this is my golang codes using pwm to control motor, FYI. https://github.com/shanghuiyang/rpi-devices/blob/master/app/car/car.go

AndrewKovalenko commented 4 years ago

I have similar issue. I try to control electric motor speed with hardware PWM. Just to test that go-rpio is working I created a simple example which suppose to make motor spinning at ~75% of max RPM:

    if err := gpio.Open(); err != nil {
        log.Printf("Error opening GPIO: %s", err.Error())
        return err
    }
    defer func() {
        gpio.StopPwm()
        gpio.Close()
    }()

    pin := gpio.Pin(18)
    pin.Pwm()
    pin.DutyCycle(3, 4)
    pin.Freq(5000 * 4) // 5000Hz * 4 cycle length
    gpio.StartPwm()

    time.Sleep(10 * time.Second)

Running this code has zero effect. Could you pls help me to troubleshoot it?

drahoslove commented 4 years ago

@AndrewKovalenko

AndrewKovalenko commented 4 years ago

@drahoslove thank you for quick response.

drahoslove commented 4 years ago

@AndrewKovalenko The RPi 4 model is not fully supported, but I merged the pull-request #50 which might solve your issue. Please try it.

AndrewKovalenko commented 4 years ago

@drahoslove thank you. I just tried to pull the latest - it seems like I still have an issue.

To exclude the problem with the motor I connected an LED instead of motor and control it from pin 18 via 2n222 transistor.

Here is a listing of my "testing app":

package main

import (
    "log"
    "time"

    gpio "github.com/stianeikeland/go-rpio/v4"
)

const cycleLength = 100
const pmwClockFrequency = 50 * cycleLength // 50kHz

func main() {
    if err := gpio.Open(); err != nil {
        log.Fatalf("Error opening GPIO: %s", err.Error())
    }

    defer func() {
        log.Println("Stop PWM")
        gpio.StopPwm()
        gpio.Close()
    }()

    pin := gpio.Pin(18)

    pin.Output()

    for i := 0; i < 10; i++ {
        log.Printf("Toggle pin. i=%d \n", i)
        pin.Toggle()
        time.Sleep(time.Second)
    }

    pin.Pwm()

    pin.Freq(pmwClockFrequency)
    log.Println("Start PWM")
    gpio.StartPwm()

    log.Println("10%")
    pin.DutyCycle(10, cycleLength)
    time.Sleep(3 * time.Second)

    log.Println("30%")
    pin.DutyCycle(30, cycleLength)
    time.Sleep(3 * time.Second)

    log.Println("50%")
    pin.DutyCycle(50, cycleLength)
    time.Sleep(3 * time.Second)

    log.Println("70%")
    pin.DutyCycle(70, cycleLength)
    time.Sleep(3 * time.Second)

    log.Println("100%")
    pin.DutyCycle(100, cycleLength)
    time.Sleep(10 * time.Second)
}

The interesting issue I observe is: when I run this app for the first time - LED is blinking while the pin is in output mode and then nothing happens in PWM mode. However if I run the same app second time - LED doesn't blink any more. It just turns on for 10 sec and goes off once pin is set to PWM. This issue persists until I reboot RasPi.

rami-dabain commented 3 years ago

related https://github.com/stianeikeland/go-rpio/issues/68