后面发现调用的两个Go的库进行测算还是没办法读到好的超声波值, 所以放弃
公式
距离(cm)=((声速(m/s)×时间(ms))/ 2) *10
代码
ultrasonicSensor.go
go
package main
import (
"context"
"errors"
"fmt"
"periph.io/x/conn/v3/gpio"
"periph.io/x/conn/v3/gpio/gpioreg"
"time"
)
var (
TimeoutError = errors.New("timeout error")
)
const (
SpeedOfSound = 34300.0 // cm/s
)
type UltrasonicSensor struct {
triggerIO gpio.PinIO
echoIO gpio.PinIO
started bool
canceled chan struct{}
}
func NewUltrasonicSensor(triggerPinName, echoPinName string) (*UltrasonicSensor, error) {
var (
us = &UltrasonicSensor{
canceled: make(chan struct{}),
}
err error
)
us.triggerIO = gpioreg.ByName(triggerPinName)
if nil == us.triggerIO {
return nil, errors.New("can't find trigger pin")
}
us.echoIO = gpioreg.ByName(echoPinName)
if nil == us.echoIO {
return nil, errors.New("can't find echo pin")
}
return us, err
}
func (u *UltrasonicSensor) Init() error {
err := u.triggerIO.Out(gpio.Low)
if nil != err {
return err
}
err = u.echoIO.In(gpio.PullDown, gpio.NoEdge)
return nil
}
func (u *UltrasonicSensor) Destroy() error {
return nil
}
func (u *UltrasonicSensor) Start(detectInterval time.Duration, onDistanceChanged func(cm float64, err error) error) error {
go u.run(detectInterval, onDistanceChanged)
return nil
}
func (u *UltrasonicSensor) run(detectInterval time.Duration, onDistanceChanged func(cm float64, err error) error) {
if u.started {
return
}
u.started = true
defer func() {
select {
case <-u.canceled:
default:
}
u.started = false
}()
var (
err error
distance float64
distanceTemp float64
/*
声速大约是343米/秒, 超声波模块最大测量是2m ~ 6m
时间(s) = 2*距离(m)/声速(m/s) = 2 * 6 / 343 ≈ 0.035
*/
maxWaitTime = time.Millisecond * 35 //35
parentCtx = context.Background()
ctx context.Context
)
for {
err = u.ultrasonicPulseOut() // 发送超声波
if nil != err {
onDistanceChanged(0, err)
return
}
ctx, _ = context.WithTimeout(parentCtx, maxWaitTime)
distanceTemp, err = u.getDist(ctx)
if nil != err {
if TimeoutError != err {
onDistanceChanged(0, err)
return
}
fmt.Println("read timeout")
time.Sleep(detectInterval)
continue
}
if distance != distanceTemp {
distance = distanceTemp
if err = onDistanceChanged(distance, nil); nil != err {
return
}
}
time.Sleep(detectInterval)
}
}
func (u *UltrasonicSensor) ultrasonicPulseOut() (err error) {
if err = u.triggerIO.Out(gpio.High); nil != err {
return err
}
time.Sleep(time.Microsecond * 10) // 10us
if err = u.triggerIO.Out(gpio.Low); nil != err {
return err
}
time.Sleep(time.Microsecond * 1)
return
}
func (u *UltrasonicSensor) getDist(ctx context.Context) (float64, error) {
var (
startDateTime time.Time // 开启超声波计时
)
waitForNext := func() error {
select {
case <-ctx.Done():
return TimeoutError
case <-u.canceled:
return errors.New("cancel error")
case <-time.After(time.Nanosecond * 1): // 读取引脚延时,也是软件最大误差
}
return nil
}
/* wait for start */
for gpio.Low == u.echoIO.Read() {
if err := waitForNext(); nil != err {
return 0, err
}
}
startDateTime = time.Now()
/* wait for end */
for gpio.High == u.echoIO.Read() {
if err := waitForNext(); nil != err {
return 0, err
}
}
return time.Since(startDateTime).Seconds() * SpeedOfSound / 2.0, nil
}
func (u *UltrasonicSensor) Stop() error {
if !u.started {
return nil
}
select {
case u.canceled <- struct{}{}:
case <-time.After(time.Second * 2):
return errors.New("cancel timeout")
}
return nil
}
main.go
go
package main
import (
"fmt"
"log"
"periph.io/x/host/v3"
"sync"
"time"
)
func main() {
var (
waiter sync.WaitGroup
)
// 初始化硬件
if _, err := host.Init(); err != nil {
log.Fatal(err)
}
sensor, err := NewUltrasonicSensor("GPIO17", "GPIO27")
if nil != err {
fmt.Println(err)
return
}
if err = sensor.Init(); nil != err {
fmt.Println("sensor init fail, ", err.Error())
return
}
defer sensor.Destroy()
waiter.Add(1)
sensor.Start(time.Second, func(cm float64, err error) error {
if nil != err {
waiter.Done()
fmt.Println(err)
return err
}
fmt.Println("Distance ", cm, "(cm)")
return nil
})
waiter.Wait()
}
Note
注意电源一定要选对, 否则输出功率不够无法准确测量距离...