使用Socket库实现树莓派小车的远程控制

一、引言

在物联网和智能硬件的时代,远程控制设备变得越来越普遍。本文将介绍如何使用 Python 编写代码来远程控制树莓派小车,实现基本的前进、后退、左转、右转和停止功能。我将详细解释代码的思路,并给出完整的代码示例。

系列文章:利用 VOFA + 调试树莓派小车 PID

系列文章:树莓派小车舵机控制-CSDN博客

系列文章:树莓派小车自动循迹之图像处理-CSDN博客

二、整体思路

整个远程控制树莓派小车的系统主要由两部分组成:服务器端(树莓派)和客户端(电脑)。服务器端负责控制小车的电机,接收客户端发送的指令并执行相应的动作;客户端负责向服务器端发送控制指令。

服务器端(server.py)

服务器端的主要任务是初始化树莓派的 GPIO 引脚,设置电机控制引脚,创建一个 TCP 套接字并监听客户端的连接。当有客户端连接时,接收客户端发送的指令,并根据指令调用相应的小车运动函数。

1、导入必要的库
import RPi.GPIO as GPIO
import socket
import time

RPi.GPIO 用于控制树莓派的 GPIO 引脚,socket 用于创建网络套接字,time 用于控制电机运行的时间。

2、设置 GPIO 模式和电机控制引脚
# 设置GPIO模式
GPIO.setmode(GPIO.BOARD)

# 定义电机控制引脚
ENA = 32
IN1 = 22
IN2 = 15
 
ENB = 33
IN3 = 16
IN4 = 18

# 电机引脚初始化为输出模式
GPIO.setup(IN1, GPIO.OUT, initial=GPIO.LOW)
GPIO.setup(IN2, GPIO.OUT, initial=GPIO.LOW)
GPIO.setup(ENB, GPIO.OUT, initial=GPIO.HIGH)
GPIO.setup(IN3, GPIO.OUT, initial=GPIO.LOW)
GPIO.setup(IN4, GPIO.OUT, initial=GPIO.LOW)
GPIO.setup(ENA, GPIO.OUT, initial=GPIO.HIGH)

# 设置电机pwm引脚和频率为100hz
pwm_ENA = GPIO.PWM(ENA, 100)
pwm_ENB = GPIO.PWM(ENB, 100)
pwm_ENA.start(0)
pwm_ENB.start(0)

这里我使用 GPIO.BOARD 模式来指定引脚编号,然后将电机控制引脚初始化为输出模式,并设置 PWM(脉冲宽度调制)引脚和频率。

3、定义小车运动函数
def forward():
    GPIO.output(IN1, GPIO.HIGH)
    GPIO.output(IN2, GPIO.LOW)
    GPIO.output(IN3, GPIO.HIGH)
    GPIO.output(IN4, GPIO.LOW)
    pwm_ENA.ChangeDutyCycle(20)
    pwm_ENB.ChangeDutyCycle(20)
    time.sleep(1)
    stop()
    print("forward")

def backward():
    GPIO.output(IN1, GPIO.LOW)
    GPIO.output(IN2, GPIO.HIGH)
    GPIO.output(IN3, GPIO.LOW)
    GPIO.output(IN4, GPIO.HIGH)
    pwm_ENA.ChangeDutyCycle(20)
    pwm_ENB.ChangeDutyCycle(20)
    time.sleep(1)
    stop()
    print("backward")

def left():
    GPIO.output(IN1, GPIO.LOW)
    GPIO.output(IN2, GPIO.LOW)
    GPIO.output(IN3, GPIO.HIGH)
    GPIO.output(IN4, GPIO.LOW)
    pwm_ENA.ChangeDutyCycle(0)
    pwm_ENB.ChangeDutyCycle(15)
    time.sleep(1)
    stop()
    print("left")

def right():
    GPIO.output(IN1, GPIO.HIGH)
    GPIO.output(IN2, GPIO.LOW)
    GPIO.output(IN3, GPIO.LOW)
    GPIO.output(IN4, GPIO.LOW)
    pwm_ENA.ChangeDutyCycle(15)
    pwm_ENB.ChangeDutyCycle(0)
    time.sleep(1)
    stop()
    print("right")

def stop():
    GPIO.output(IN1, GPIO.LOW)
    GPIO.output(IN2, GPIO.LOW)
    GPIO.output(IN3, GPIO.LOW)
    GPIO.output(IN4, GPIO.LOW)
    pwm_ENA.ChangeDutyCycle(0)
    pwm_ENB.ChangeDutyCycle(0)

这些函数分别控制小车的前进、后退、左转、右转和停止。通过设置 GPIO 引脚的电平状态和 PWM 占空比来控制电机的转动方向和速度。

4、创建网络套接字并监听客户端连接
# 创建socket对象
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 获取本地主机名
host = "192.168.152.246" #此处为你的树莓派ip地址
port = 12345

# 绑定端口
server_socket.bind((host, port))

# 设置最大连接数,超过后排队
server_socket.listen(5)

while True:
    # 建立客户端连接
    client_socket, addr = server_socket.accept()
    print("连接地址: %s" % str(addr))
    try:
        while True:
            # 接收客户端消息
            data = client_socket.recv(1024).decode('utf-8')
            if not data:
                break
            if data == 'forward':
                forward()
            elif data == 'backward':
                backward()
            elif data == 'left':
                left()
            elif data == 'right':
                right()
            elif data == 'stop':
                stop()
    except Exception as e:
        print(f"发生错误: {e}")
    finally:
        # 关闭客户端连接
        client_socket.close()

# 清理GPIO设置
GPIO.cleanup()

这里我创建了一个 TCP 套接字,绑定到指定的主机和端口,并开始监听客户端的连接。当有客户端连接时,接收客户端发送的指令,并根据指令调用相应的小车运动函数。

客户端(client.py)

客户端的主要任务是创建一个 TCP 套接字,连接到服务器端,然后通过用户输入的指令向服务器端发送控制指令。

1、导入必要的库
import socket

socket 用于创建网络套接字。

2、创建套接字并连接到服务器
# 创建socket对象
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 获取服务器的主机名
host = "192.168.152.246" #此处为你的树莓派ip地址
port = 12345

# 连接服务,指定主机和端口
client_socket.connect((host, port))

这里我创建了一个 TCP 套接字,并连接到服务器端的指定主机和端口。

3、接收用户输入并发送指令
while True:
    command = input("请输入控制指令 (forward/backward/left/right/stop/exit): ")
    if command == 'exit':
        break
    # 发送指令到服务器
    client_socket.send(command.encode('utf-8'))

# 关闭连接
client_socket.close()

这里我通过一个循环不断接收用户输入的指令,当用户输入 exit 时,退出循环并关闭连接。否则,将指令编码为 UTF-8 格式并发送到服务器端。

三、完整代码

1、server.py

import RPi.GPIO as GPIO
import socket
import time

# 设置GPIO模式
GPIO.setmode(GPIO.BOARD)

# 定义电机控制引脚
ENA = 32
IN1 = 22
IN2 = 15
 
ENB = 33
IN3 = 16
IN4 = 18

# 电机引脚初始化为输出模式

global pwm_ENA
global pwm_ENB
    
GPIO.setup(IN1, GPIO.OUT, initial=GPIO.LOW)
GPIO.setup(IN2, GPIO.OUT, initial=GPIO.LOW)
GPIO.setup(ENB, GPIO.OUT, initial=GPIO.HIGH)
GPIO.setup(IN3, GPIO.OUT, initial=GPIO.LOW)
GPIO.setup(IN4, GPIO.OUT, initial=GPIO.LOW)
GPIO.setup(ENA, GPIO.OUT, initial=GPIO.HIGH)
# 设置电机pwm引脚和频率为100hz
pwm_ENA = GPIO.PWM(ENA, 100)
pwm_ENB = GPIO.PWM(ENB, 100)
pwm_ENA.start(0)
pwm_ENB.start(0)

# 定义小车运动函数
def forward():
    GPIO.output(IN1, GPIO.HIGH)
    GPIO.output(IN2, GPIO.LOW)
    GPIO.output(IN3, GPIO.HIGH)
    GPIO.output(IN4, GPIO.LOW)
    pwm_ENA.ChangeDutyCycle(20)
    pwm_ENB.ChangeDutyCycle(20)
    time.sleep(1)
    stop()
    print("forward")

def backward():
    GPIO.output(IN1, GPIO.LOW)
    GPIO.output(IN2, GPIO.HIGH)
    GPIO.output(IN3, GPIO.LOW)
    GPIO.output(IN4, GPIO.HIGH)
    pwm_ENA.ChangeDutyCycle(20)
    pwm_ENB.ChangeDutyCycle(20)
    time.sleep(1)
    stop()
    print("backward")

def left():
    GPIO.output(IN1, GPIO.LOW)
    GPIO.output(IN2, GPIO.LOW)
    GPIO.output(IN3, GPIO.HIGH)
    GPIO.output(IN4, GPIO.LOW)
    pwm_ENA.ChangeDutyCycle(0)
    pwm_ENB.ChangeDutyCycle(15)
    time.sleep(1)
    stop()
    print("left")

def right():
    GPIO.output(IN1, GPIO.HIGH)
    GPIO.output(IN2, GPIO.LOW)
    GPIO.output(IN3, GPIO.LOW)
    GPIO.output(IN4, GPIO.LOW)
    pwm_ENA.ChangeDutyCycle(15)
    pwm_ENB.ChangeDutyCycle(0)
    time.sleep(1)
    stop()
    print("right")

def stop():
    GPIO.output(IN1, GPIO.LOW)
    GPIO.output(IN2, GPIO.LOW)
    GPIO.output(IN3, GPIO.LOW)
    GPIO.output(IN4, GPIO.LOW)
    pwm_ENA.ChangeDutyCycle(0)
    pwm_ENB.ChangeDutyCycle(0)

# 创建socket对象
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 获取本地主机名
host = "192.168.152.246"
port = 12345

# 绑定端口
server_socket.bind((host, port))

# 设置最大连接数,超过后排队
server_socket.listen(5)

while True:
    # 建立客户端连接
    client_socket, addr = server_socket.accept()
    print("连接地址: %s" % str(addr))
    try:
        while True:
            # 接收客户端消息
            data = client_socket.recv(1024).decode('utf-8')
            if not data:
                break
            if data == 'forward':
                forward()
            elif data == 'backward':
                backward()
            elif data == 'left':
                left()
            elif data == 'right':
                right()
            elif data == 'stop':
                stop()
    except Exception as e:
        print(f"发生错误: {e}")
    finally:
        # 关闭客户端连接
        client_socket.close()

# 清理GPIO设置
GPIO.cleanup()
    

2、client.py

import socket

# 创建socket对象
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 获取服务器的主机名
host = "192.168.152.246"
port = 12345

# 连接服务,指定主机和端口
client_socket.connect((host, port))

while True:
    command = input("请输入控制指令 (forward/backward/left/right/stop/exit): ")
    if command == 'exit':
        break
    # 发送指令到服务器
    client_socket.send(command.encode('utf-8'))

# 关闭连接
client_socket.close()
    

四、运行代码

  1. 在树莓派上运行server.py脚本。

  2. 在客户端设备(如电脑)上运行client.py脚本。

  3. 在客户端输入控制指令,即可控制树莓派小车的运动。

五、注意事项

  • 要保证树莓派和客户端设备处于同一网络中。

  • host = "192.168.152.246"  此处为你的树莓派ip地址

六、可能遇到的问题

我在运行client,py时遇到

Traceback (most recent call last): File "C:\Users\25518\Desktop\client.py", line 11, in <module> client_socket.connect((host, port)) ConnectionRefusedError: [WinError 10061] 由于目标计算机积极拒绝,无法连接。

原因是因为windows有防火墙限制

我的解决办法是 在防火墙的入站规则中添加允许 Python 程序通过 12345 端口的规则

打开 “Windows Defender 防火墙高级安全”

在 “Windows Defender 防火墙高级安全” 窗口的左侧面板中,右键单击 “入站规则”,然后选择 “新建规则”。

在弹出的 “新建入站规则向导” 中,选择 “端口”,然后点击 “下一步”。

选择 “特定本地端口”,输入 12345,然后点击 “下一步”。

选择 “允许连接”,然后点击 “下一步”。

可以根据自己的需求勾选 “域”“专用”“公用” 网络类型,然后点击 “下一步”。

为规则命名,例如 “Python 12345 端口入站规则”,可以添加描述信息以便后续识别,然后点击 “完成”。

七、总结

通过以上步骤,你就能成功搭建并实现树莓派小车的远程控制。实现之后还可以进一步拓展小车功能,如添加pid算法,增加舵机控制等等,让树莓派小车更加智能。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值