[树莓派] 轻松制作一个遥控小车(C++,Socket)

Posted Weasker威斯克

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[树莓派] 轻松制作一个遥控小车(C++,Socket)相关的知识,希望对你有一定的参考价值。

最近闲来无事,便开始倒腾一些小玩具。我想从比较简单的开始入手,就先是树莓派遥控小汽车吧!
本文用来分享和总结经验。从0开始,小白级教程。

一.必备材料:

1.树莓派 1 个(什么版本都可以)
2.智能小车底盘 1 套(带电机)
3.L298N电机驱动板模块 1 个(3轮最多一个,4轮可以两个,但是需要更多电池,不推荐)
4.公对母杜邦线×8、普通导线×8
5.螺丝刀、扎带、小型充电宝
6.5号电池 4 节

二.小车组件安装

1.电机接线
按照下图,将电机的两端用两根导线相连,玩过四驱车的肯定都懂。因为是直流电机,所以不存在正负之分,随便连,剩下三个复制此操作。

2.L298N模块接线

AB:电机1接口,将一组电机导线两端分别接上。
CD:电机2接口,将另一组电机导线两端分别接上。
E:接电池正极,由于4节干电池电压不够,所以最好将树莓派+5V GPIO引脚也接入。
F:接电池负极。
G:接树莓派+5V GPIO引脚。
HIJK:IN1、IN2、IN3、IN4(IN1和IN2控制AB组电机,IN3和IN4控制CD组电机)。

3.树莓派GPIO接线
树莓派4b的GPIO接口图

由上图可知树莓派的GPIO口有7、11、12、13、15、16、18、22、29、31、32、33、36、37,小车只需用到4个即可(还有两个+5V口)。
将IN1、IN2、IN3、IN4分别接到GPIO口7、11、13、15位置。
(图中红色的是散热扇的线,请忽略)
4.车身固定
先将4个电机装好,再用扎带将电池盒、L298N模块、树莓派固定在底盘上,树莓派最好使用移动电源供电,所以部件摆放位置可以自由发挥。

二.代码实现

在终端输入

mkidr /home/pi/car #创建car目录
cd /home/pi/car #进入car目录
touch up.py #创建python文件
vim up.py #编辑python文件

然后在编辑器中按下"i"进入插入编辑模式并输入下面的代码。

"up.py"

import RPi.GPIO as GPIO
import time
GPIO.setmode(GPIO.BOARD) #设置GPIO口引用模式

IN1 = 7   #引用刚才接线的GPIO口
IN2 = 11
IN3 = 13
IN4 = 15
GPIO.setup(IN1,GPIO.OUT)  #设置GPIO口为输出模式
GPIO.setup(IN2,GPIO.OUT)
GPIO.setup(IN3,GPIO.OUT)
GPIO.setup(IN4,GPIO.OUT)

GPIO.output(IN1,GPIO.HIGH)  #根据L298N的操作说明来改变电平
GPIO.output(IN2,GPIO.LOW)
GPIO.output(IN3,GPIO.LOW)
GPIO.output(IN4,GPIO.HIGH)

输入完后按下"ESC"退出编辑模式,英文输入法下输入":“并输入"wq"保存退出(详情见VIM编辑器使用方法)
代码中的变量IN1和IN2控制第一组电机,IN3和IN4控制第二组电机。

上面的代码是负责前进的,根据他我们再创建"down.py”、“left.py”、“right.py”、"stop.py"四个python文件并修改对应的代码。

"down.py"

GPIO.output(IN1,GPIO.LOW)
GPIO.output(IN2,GPIO.HIGH)
GPIO.output(IN3,GPIO.HIGH)
GPIO.output(IN4,GPIO.LOW)

"left.py"

GPIO.output(IN1,GPIO.LOW)
GPIO.output(IN2,GPIO.HIGH)
GPIO.output(IN3,GPIO.LOW)
GPIO.output(IN4,GPIO.HIGH)

"right.py"

GPIO.output(IN1,GPIO.HIGH)
GPIO.output(IN2,GPIO.LOW)
GPIO.output(IN3,GPIO.HIGH)
GPIO.output(IN4,GPIO.LOW)

"stop.py"

GPIO.output(IN1,GPIO.LOW)
GPIO.output(IN2,GPIO.LOW)
GPIO.output(IN3,GPIO.LOW)
GPIO.output(IN4,GPIO.LOW)

此时我们的树莓派对GPIO的管理代码已经完毕,在终端输入:

sudo python up.py

即可调用"up.py"使小车转起来。
再输入:

sudo python stop.py

即可让小车停下。
这里可能的问题
1.只有一两根轮子能转:说明电压不够,返回步骤"二-2"查看E接口,有没有将树莓派+5V接入。
2.轮子转动方向不同:说明电机接线反了或者代码里电平给错了,按组排查即可。

到了这里,小车就算是能跑起来了!但是不要沾沾自喜,还有很多功能等待你发掘。

用"sudo python XX.py"控制小车是不是非常蛋疼?由于python是为了玩这个紧急学习的,了解的并不多,所以我这里决定使用C++来编写一个socket通信来通过图形界面控制小车,也就是做个遥控器。这里只展示PC上的遥控器。

三.进阶遥控(选修)

1.服务端
我让树莓派作为服务端,在/home/pi/car路径下新建一个文件叫"CarServer.cpp"(确保你的树莓派装有g++用来编译.cpp文件,新一点的树莓派都自带,安装方法自行百度)。
使用vim CarServer.cpp进行编辑并将下面的代码复制进去。

#include <iostream>
#include <unistd.h>
#include <cstring>
#include <string>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <cstdlib>
using namespace std;
#define USEPORT 1234

int main()

	//****创建套接字
	int serverSock = socket(AF_INET, SOCK_STREAM, 0);
	//Windows中,AF_INET==PF_INET
	//Linux中,不同的版本这两者有微小差别.对于BSD是AF,对于POSIX是PF
	if (serverSock < 0)
		cout << "socket creation failed" << endl;
		exit(-1);
	
	cout << "socket creation successfully" << endl;
	//****绑定ip和端口
	struct sockaddr_in serverAddr;
	memset(&serverAddr, 0, sizeof(serverAddr));
	serverAddr.sin_family = AF_INET;
	serverAddr.sin_port = htons(USEPORT);
	//INADDR_ANY绑定所有IP
	serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);
	//****绑定套接字
	if (bind(serverSock,(struct sockaddr*)&serverAddr,sizeof(struct sockaddr)) == -1)
		cout << "Bind error, Port[" << USEPORT << "]" << endl;
		exit(-1);
	
	cout << "Bind successfully" << endl;

	//****监听
	if (listen(serverSock, 10) == -1)
		cout << "Listen error!" << endl;
	
	cout << "Listening on port[" << USEPORT << "]" << endl;

	//****开始接收accept()
	struct sockaddr clientAddr;
	int size = sizeof(struct sockaddr);

	int clientSock = accept(serverSock, (struct sockaddr*)&clientAddr, (socklen_t*)&size);

	cout << "The Controler Connected!" << endl;
	system("sudo python stop.py");
	//****通信
	while (1)
		char revData[5];
		int ret = recv(clientSock,revData,5,0);
		if(ret > 0)
			revData[ret] = 0x00;
			cout<<"retrevData:"<<revData<<endl;
		
		cout<<"lenth:"<<ret<<endl;
		cout<<"revData:"<<revData<<endl;
		if(strcmp(revData, "UPUP") == 0)
			cout<<"up"<<endl;
			system("ls");
			system("sudo python up.py");
		
		else if(strcmp(revData,"DOWN") == 0)
			system("sudo python down.py");
			printf("down");
		
		else if(strcmp(revData,"LEFT") == 0)
			system("sudo python left.py");
			printf("left");
		
		else if(strcmp(revData,"RIGHT") == 0)
			system("sudo python right.py");
			printf("right");
		
		else if(strcmp(revData,"STOP") == 0)
			system("sudo python stop.py");
			printf("stop");
		
		else if(strcmp(revData,"QUIT") == 0)
			cout<<"shutdown"<<endl;
			break;
		
	

	close(serverSock);
	return 0;

保存后在终端输入:

g++ CarServer.cpp

服务端就编写完了。

2.客户端
(1).在Qt Creator中,新建一个Qt Widgets Application项目,Build system选择qmake,基类选择QMainWindow。

(2).进入设计页面添加6个按钮和1个标签

(3).将4个控制上下左右的按钮的objectName改为:UpButton、DownButton、LeftButton、RightButton。
(4).将两个控制服务连接的按钮objectName改为:ConnectButton、BreakButton。(按钮的objectName可以自定义,不过下面的代码里也要跟着改)(双击组件可以修改标题名称)

(5).返回编辑页面,在.pro文件里添加:

QT += network
LIBS += -lpthread libwsock32 libws2_32

(6).在.h文件的构造函数的public里添加:

QTcpSocket* socket;

(7).在.h文件的构造函数里的public和private之间添加:

private slots:
    void on_ConnectButton_clicked();

    void on_UpButton_pressed();

    void on_UpButton_released();

    void on_BreakButton_clicked();

    void on_DownButton_pressed();

    void on_DownButton_released();

    void on_LeftButton_pressed();

    void on_LeftButton_released();

    void on_RightButton_pressed();

    void on_RightButton_released();

(8).进入mainwindow.cpp并将下面代码复制进去(注意修改下面的IP,每个人都不同):

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "iostream"
#include "string"
#include "winsock2.h"
#include <QApplication>
using namespace std;
MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)

    ui->setupUi(this);
    socket = new QTcpSocket();
    QObject::connect(socket,&QTcpSocket::readyRead,this,&MainWindow::on_ConnectButton_clicked);


MainWindow::~MainWindow()

    delete ui;


void MainWindow::on_ConnectButton_clicked()

    socket->abort();
    socket->connectToHost("192.168.3.30",1234); //这里修改为你树莓派的IP,端口是服务端里设置的
    if(!socket->waitForConnected(30000))
        ui->label->setText("连接失败,请重试!");
    else
        ui->label->setText("连接成功!");


void MainWindow::on_UpButton_pressed()

    socket->write("UPUP");


void MainWindow::on_UpButton_released()

    socket->write("STOP");


void MainWindow::on_BreakButton_clicked()

    socket->write("QUIT");
    ui->label->setText("未连接!");


void MainWindow::on_DownButton_pressed()

    socket->write("DOWN");


void MainWindow::on_DownButton_released()

    socket->write("STOP");


void MainWindow::on_LeftButton_pressed()

    socket->write("LEFT");


void MainWindow::on_LeftButton_released()

    socket->write("STOP");


void MainWindow::on_RightButton_pressed()

    socket->write("RIGHT");


void MainWindow::on_RightButton_released()

    socket->write("STOP");

3.开始连接
先在Qt Creator中点击运行,然后在树莓派终端/home/pi/car路径下先输入:

g++ CarServer.cpp
./a.out

运行CarServer.cpp,此时点击连接按钮,终端显示连接成功。

此时点击"↑",服务端会显示信息说明通信成功。
出现"stop.py:RuntimeWarning:This channel is already in use, continuing anyway. Use GPIO.setwarnings(False) to disable warning.”忽视即可。

至此小车就可以通过windows遥控了!

Bili视频教程:https://www.bilibili.com/video/BV1Di4y1E7dr/
如果过程中有问题欢迎私信我!记得关注喔!

以上是关于[树莓派] 轻松制作一个遥控小车(C++,Socket)的主要内容,如果未能解决你的问题,请参考以下文章

树莓派制作遥控小车-新手教程

如何用一部红外遥控器来遥控操作树莓派上安装的影音中心

树莓派小车By 树莓派爱好者ITJoker(通过C socket通信实现树莓派视频小车)

使用树莓派DIY个人智能设备

用树莓派的方式打开小米手机:摇晃手机控制小车,前进后退加转弯,成本不到350元 | 开源...

求助树莓派避障小车,遇到 python 了