遥控小车(基于TCP/IP)

        其实我更想用32的板子来完成这个项目,但是老师要求只能用GEC6818的板子,虽然这个板子功能更加全面,但本人还是对32熟悉一些,所以前期还是花了很多时间来研究这块板子,总的来说其实步骤还是差不多的。实现代码在文章最底下。

1、总体设计任务框图

2、设计任务:

本设计是基于粤嵌gec6818开发板完成远端操控小车的操作,小车需要纯手工组装。

要求:

完成各模块功能的构建,使用QT的界面设计和安卓配置作为客户端给服务器端发送数据,在服务器端接收数据并创建子线程处理数据。通过看6818底板电路图发现可使用GPIO_C7、C8、C17和GPIO_E13输出电平给电机供电,并且可通过调节占空比来控制小车速度。

3、功能要求及技术指标

  1. 完成各模块功能的构建,要求掌握客户端相关功能的构建,要求掌握驱动相关功能的构建,要求掌握服务器端相关功能的构建。
  2. 完成各模块程序设计与编写要求掌握TCP网络编程的基本功能和作用,要求掌握驱动控制实现电机转动,要求掌握基于QT5和Android的界面设计。
  3. 完成各项性能测试,要求实现客户端与服务器端的连接,要求实现电机驱动及速度控制,要求实现按钮控制小车。
  4. 完成最终应用程序功能的组合,要求通过TCP网络编程、QT和Android界面设计和驱动编译组合实现控制小车跑。

4、 总体设计方案

        运用QT实现基本的TCP客户端和服务器端的基本通信,客户端实现与服务器端建立连接、发送数据与断开,服务器端接收客户端数据并创建子线程来处理接收到的数据。再通过UI和安卓界面设计来实现按钮控制小车,再通过给四个GPIO口输出高低电平来控制电机转动和速度,最后实现控制小车。

5 系统测试

客户端:QT版与安卓版

(ps:奥迪rs7是不是你的终极梦想,哈哈哈)

 

服务器端:基于粤嵌6818的智能小车

6 使用说明

        当你在输入框内输入正确的IP地址以及端口号,点击链接即可成功并在显示窗口显示连接成功,然后就可以通过点击前进,后退,左转,右转,停止来实现控制小车运动,点击断开及失去控制权。

7.附录代码

服务器端:

int port = 6666;

// GPIOC7的编号为: PAD_GPIO_C + 7

enum {

    PAD_GPIO_A      = (0 * 32),

    PAD_GPIO_B      = (1 * 32),

    PAD_GPIO_C      = (2 * 32),

    PAD_GPIO_D      = (3 * 32),

    PAD_GPIO_E      = (4 * 32),

    PAD_GPIO_ALV    = (5 * 32),

};

//GPIO模式

#define GPIO_MODE_INPUT  1

#define GPIO_MODE_OUTPUT  0

#define THREAD_NUMBER       1  

typedef struct gpio_cfg_t

{

unsigned int gpio_no; //gpio的编号

unsigned int gpio_mode; // input/output

unsigned int init_value; // 当gpio配置成output模式时

 //指定输出的初始值。

}gpio_cfg_t;

typedef struct gpio_value

{

unsigned int gpio_no; //gpio的编号

unsigned int gpio_value;

} gpio_value_t;

#define GPIO_CONFIG  _IOW('G', 1, gpio_cfg_t)

#define GPIO_SET_VALUE _IOW('G', 2, gpio_value_t)

#define GPIO_GET_VALUE _IOWR('G', 3, gpio_value_t)

gpio_cfg_t gpio_init;

gpio_value_t gpio_clear;

void GPIO_Init(int fd)

{

gpio_init.gpio_no = PAD_GPIO_C + 7;

gpio_init.gpio_mode = GPIO_MODE_OUTPUT; //输出模式

gpio_init.init_value = 0; //初始输出 低电平 

ioctl(fd, GPIO_CONFIG, &gpio_init);

gpio_init.gpio_no =  PAD_GPIO_C + 8;

        gpio_init.gpio_mode = GPIO_MODE_OUTPUT; //输出模式

        gpio_init.init_value = 0; //初始输出 低电平 

        ioctl(fd, GPIO_CONFIG, &gpio_init);

        gpio_init.gpio_no =  PAD_GPIO_C + 17;

        gpio_init.gpio_mode = GPIO_MODE_OUTPUT; //输出模式

        gpio_init.init_value = 0; //初始输出 低电平 

        ioctl(fd, GPIO_CONFIG, &gpio_init);

        gpio_init.gpio_no =  PAD_GPIO_E + 13 ;

        gpio_init.gpio_mode = GPIO_MODE_OUTPUT; //输出模式

        gpio_init.init_value = 0; //初始输出 低电平 

        ioctl(fd, GPIO_CONFIG, &gpio_init);

}

void clear(int fd)

{

gpio_clear.gpio_no = PAD_GPIO_C + 7;

gpio_clear.gpio_value = 0;

ioctl(fd, GPIO_SET_VALUE, &gpio_clear);

        gpio_clear.gpio_no = PAD_GPIO_C + 8;

        gpio_clear.gpio_value = 0;

        ioctl(fd, GPIO_SET_VALUE, &gpio_clear);

        gpio_clear.gpio_no = PAD_GPIO_C + 17;

        gpio_clear.gpio_value = 0;

        ioctl(fd, GPIO_SET_VALUE, &gpio_clear);

        gpio_clear.gpio_no =  PAD_GPIO_E + 13;

        gpio_clear.gpio_value = 0;

        ioctl(fd, GPIO_SET_VALUE, &gpio_clear);

}

void forward(int fd)

{

gpio_value_t gpio_value_1;

gpio_value_1.gpio_no = PAD_GPIO_C + 7;

gpio_value_1.gpio_value = 1;

ioctl(fd, GPIO_SET_VALUE, &gpio_value_1);

        gpio_value_t gpio_value_2;

        gpio_value_2.gpio_no = PAD_GPIO_E + 13;

        gpio_value_2.gpio_value = 1;

        ioctl(fd, GPIO_SET_VALUE, &gpio_value_2);

 gpio_value_t gpio_value_C8;

        gpio_value_C8.gpio_no = PAD_GPIO_C + 8;

        gpio_value_C8.gpio_value = 0;

        ioctl(fd, GPIO_SET_VALUE, &gpio_value_C8);

        gpio_value_t gpio_value_C17;

        gpio_value_C17.gpio_no = PAD_GPIO_C + 17;

        gpio_value_C17.gpio_value = 0;

        ioctl(fd, GPIO_SET_VALUE, &gpio_value_C17);

}

void back(int fd)

{

gpio_value_t gpio_value_3;

        gpio_value_3.gpio_no = PAD_GPIO_C + 8;

        gpio_value_3.gpio_value = 1;

        ioctl(fd, GPIO_SET_VALUE, &gpio_value_3);

        gpio_value_t gpio_value_4;

        gpio_value_4.gpio_no = PAD_GPIO_C + 17;

        gpio_value_4.gpio_value = 1;

        ioctl(fd, GPIO_SET_VALUE, &gpio_value_4);

        gpio_value_t gpio_value_C7;

        gpio_value_C7.gpio_no = PAD_GPIO_C + 7;

        gpio_value_C7.gpio_value = 0;

        ioctl(fd, GPIO_SET_VALUE, &gpio_value_C7);

        gpio_value_t gpio_value_E13;

        gpio_value_E13.gpio_no = PAD_GPIO_E + 13;

        gpio_value_E13.gpio_value = 0;

        ioctl(fd, GPIO_SET_VALUE, &gpio_value_E13);

}

void turn_left(int fd)

{

gpio_value_t gpio_value_5;

gpio_value_5.gpio_no = PAD_GPIO_C + 7;

gpio_value_5.gpio_value = 1;

ioctl(fd, GPIO_SET_VALUE, &gpio_value_5);

        gpio_value_t gpio_value_6;

        gpio_value_6.gpio_no = PAD_GPIO_C + 8;

        gpio_value_6.gpio_value = 0;

        ioctl(fd, GPIO_SET_VALUE, &gpio_value_6);

        gpio_value_t gpio_value_C17;

        gpio_value_C17.gpio_no = PAD_GPIO_C + 17;

        gpio_value_C17.gpio_value = 0;

        ioctl(fd, GPIO_SET_VALUE, &gpio_value_C17);

        gpio_value_t gpio_value_E13;

        gpio_value_E13.gpio_no = PAD_GPIO_E + 13;

        gpio_value_E13.gpio_value = 0;

        ioctl(fd, GPIO_SET_VALUE, &gpio_value_E13);

// sleep(1);

// forward(fd);

}

void turn_right(int fd)

{

gpio_value_t gpio_value_7;

gpio_value_7.gpio_no = PAD_GPIO_C + 17;

gpio_value_7.gpio_value = 1;

ioctl(fd, GPIO_SET_VALUE, &gpio_value_7);

        gpio_value_t gpio_value_8;

        gpio_value_8.gpio_no = PAD_GPIO_E + 13;

        gpio_value_8.gpio_value = 0;

        ioctl(fd, GPIO_SET_VALUE, &gpio_value_8);

        gpio_value_t gpio_value_C7;

        gpio_value_C7.gpio_no = PAD_GPIO_C + 7;

        gpio_value_C7.gpio_value = 0;

        ioctl(fd, GPIO_SET_VALUE, &gpio_value_C7);

        gpio_value_t gpio_value_C8;

        gpio_value_C8.gpio_no = PAD_GPIO_C + 8;

        gpio_value_C8.gpio_value = 0;

        ioctl(fd, GPIO_SET_VALUE, &gpio_value_C8);

// sleep(1);

// forward(fd);

}

/*处理接收客户端消息函数*/

int ret;

void *recv_message(void *fd)

{

int sockfd = *(int *)fd;

int i,j,k,n;

        printf("received from client:%d\n", ret);

while(1)

{

  

switch(ret)

{

case 0:clear(sockfd);break;

case 1:

        for(i = 0;i < 10;i++)

         {

                 if(i == 0 | i == 4 | i == 7)

                 {

                         forward(sockfd);

                 }

                 else

                 {

                         clear(sockfd);

                 }

         }

// forward(sockfd);

break;

case 2:

                for(j = 0;j < 10;j++)

                  {

                        if(j == 0 | j == 4 | j == 7)

                         {

                                back(sockfd);

                        }

                         else

                         {

                                clear(sockfd);

                         }

                 }

// back(sockfd);

break;

case 3:

                for(k = 0;k < 10;k++)

                  {

                        if(k == 0 |k == 4 |k ==7)

                         {

                                turn_left(sockfd);

                        }

                         else

                         {

                                clear(sockfd);

                         }

                 }

// turn_left(sockfd);

break;

case 4:

                for(n = 0;n < 10;n++)

                  {

                        if(n == 0 | n == 4 | n == 7)

                         {

                                turn_right(sockfd);

                        }

                         else

                         {

                                clear(sockfd);

                         }

                 }

// turn_right(sockfd);

break;

default:printf("recivice error");break;

}

}//while

}

int main()

{

     int fd = open("/dev/gec6818_gpios", O_RDWR);

     if (fd == -1)

     {

             perror("failed to open:");

             return -1;

     }

//声明套接字

int listenfd , connfd;

socklen_t clilen;

//声明线程ID

pthread_t recv_tid , send_tid;

//定义地址结构

struct sockaddr_in servaddr , cliaddr;

GPIO_Init(fd);

/*(1) 创建套接字*/

if((listenfd = socket(AF_INET , SOCK_STREAM , 0)) == -1)

{

perror("socket error.\n");

exit(1);

}//if

/*(2) 初始化地址结构*/

bzero(&servaddr , sizeof(servaddr));

servaddr.sin_family = AF_INET;

servaddr.sin_addr.s_addr = htonl(INADDR_ANY);

servaddr.sin_port = htons(port);

/*(3) 绑定套接字和端口*/

if(bind(listenfd , (struct sockaddr *)&servaddr , sizeof(servaddr)) < 0)

{

perror("bind error.\n");

exit(1);

}//if

/*(4) 监听*/

if(listen(listenfd , LISTENQ) < 0)

{

perror("listen error.\n");

exit(1);

}//if

/*(5) 接受客户请求,并创建线程处理*/

clilen = sizeof(cliaddr);

if((connfd = accept(listenfd , (struct sockaddr *)&cliaddr , &clilen)) < 0)

{

perror("accept error.\n");

exit(1);

}//if

printf("server: got connection from %s\n", inet_ntoa(cliaddr.sin_addr));

        /*创建子线程处理该客户链接接收消息*/

        if( pthread_create(&recv_tid , NULL , recv_message, &fd) == -1)

        {

                perror("pthread create error.\n");

                exit(1);

        }

while(1)

{

 char buf[MAX_LINE];

memset(buf , 0 , MAX_LINE);

int n;

if((n = recv(connfd , buf , MAX_LINE , 0)) == -1)

{

perror("recv error.\n");

exit(1);

}

sscanf(buf,"%d",&ret);

}

}

客户端:

安卓:

ui->ctnForward->setFixedSize(200,200);

        ui->ctnBack->setFixedSize(200,200);

        ui->ctnLeft->setFixedSize(200,200);

        ui->ctnRight->setFixedSize(200,200);

        ui->textshow->setFixedSize(800,500);

        ui->ctnStop->setFixedSize(200,200);

        ui->ctnStop->move(400,1000);

        ui->ctnForward->move(400,770);

        ui->ctnBack->move(400,1230);

        ui->ctnLeft->move(100,1000);

        ui->ctnRight->move(700,1000);

        ui->textshow->move(150,100);

        ui->lineEditip->setFixedSize(600,100);

        ui->lineEditport->setFixedSize(600,100);

        ui->lineEditip->move(360,1500);

        ui->lineEditport->move(360,1650);

        ui->labelip->setFixedSize(150,100);

        ui->labelport->setFixedSize(150,100);

        ui->labelip->move(150,1500);

        ui->labelport->move(150,1650);

        ui->ctnConnect->setFixedSize(200,100);

        ui->ctnDisconnect->setFixedSize(200,100);

        ui->ctnConnect->move(200,1900);

        ui->ctnDisconnect->move(600,1900);

    //连接小车

void TCPcar2::on_ctnConnect_clicked()

{

    //获取IP和端口号

    QString ip=ui->lineEditip->text();

    qint16 port = ui->lineEditport->text().toInt();//字符串转换成整形

    //主动与服务器建立连接

    tcpSocket->connectToHost(QHostAddress(ip),port);

}

    //断开连接

void TCPcar2::on_ctnDisconnect_clicked()

{

    //断开连接

        tcpSocket->disconnectFromHost();

        tcpSocket->close();

}

    //前进

void TCPcar2::on_ctnForward_pressed()

{

    QString str1="1";

       tcpSocket->write(str1.toUtf8().data());//给小车发送数据    Utf8将qstring转qbytearray  .data()转char

         ui->textshow->setText("向前冲冲冲");

         //qDebug()<<"1";

}

void TCPcar2::on_ctnForward_released()

{

//    QString str0="0";

//        tcpSocket->write(str0.toUtf8().data());

//         qDebug()<<"0";

}

    //后退

void TCPcar2::on_ctnBack_pressed()

{

    QString str2="2";

       tcpSocket->write(str2.toUtf8().data());

         ui->textshow->setText("倒车请注意哟");

         //qDebug()<<"2";

}

void TCPcar2::on_ctnBack_released()

{

//    QString str0="0";

//    tcpSocket->write(str0.toUtf8().data());

//     qDebug()<<"0";

}

    //左转

void TCPcar2::on_ctnLeft_pressed()

{

    QString str3="3";

        tcpSocket->write(str3.toUtf8().data());//给小车发送数据

           ui->textshow->setText("左转啦");

           //qDebug()<<"3";

}

void TCPcar2::on_ctnLeft_released()

{

//    QString str0="0";

//    tcpSocket->write(str0.toUtf8().data());

//     qDebug()<<"0";

}

    //  右转

void TCPcar2::on_ctnRight_pressed()

{

    QString str4="4";

       tcpSocket->write(str4.toUtf8().data());

         ui->textshow->setText("右转啦");

         //qDebug()<<"4";

}

void TCPcar2::on_ctnRight_released()

{

//    QString str0="0";

//    tcpSocket->write(str0.toUtf8().data());

//     qDebug()<<"0";

}

//添加绘图事件,QPixmap(":/image/2.png"));里面加的

//是添加资源的路径,

    //添加背景图

//void TCPcar2::paintEvent(QPaintEvent *event)

//{

//    QPainter painter(this);

//    painter.drawPixmap(0,0,width(),height(),QPixmap("C:/Users/12085/Pictures/Saved Pictures/rs7.jpg"));

//}

void TCPcar2::on_ctnStop_clicked()

{

    QString str0="0";

        tcpSocket->write(str0.toUtf8().data());

         //qDebug()<<"0";

        ui->textshow->setText("刹车啦!!!!!!");

}

驱动:


#include <linux/fs.h>
#include <asm/segment.h>
#include <asm/uaccess.h>
#include <linux/buffer_head.h>

#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/ioctl.h>

#include <linux/fs.h>
#include <linux/gpio.h>
#include <cfg_type.h>

#include <linux/miscdevice.h>

MODULE_LICENSE("GPL");

#define GPIO_MODE_INPUT  1 
#define GPIO_MODE_OUTPUT  0

typedef struct gpio_cfg_t
{
    unsigned int gpio_no; //gpio的编号
    unsigned int gpio_mode; // input/output

    unsigned int init_value; // 当gpio配置成output模式时
                             //输出的初始值。
}gpio_cfg_t;


typedef struct gpio_value
{    
    unsigned int gpio_no; //gpio的编号
    unsigned int gpio_value; // 
} gpio_value_t;


#define GPIO_CONFIG  _IOW('G', 1, gpio_cfg_t)
#define GPIO_SET_VALUE _IOW('G', 2, gpio_value_t)
#define GPIO_GET_VALUE _IOWR('G', 3, gpio_value_t)


long gec6818_gpio_ioctl (struct file *_file, unsigned int cmd, unsigned long arg)
{
    gpio_cfg_t gpio_cfg;
    gpio_value_t gpio_value;
    char gpio_name[12];
    int ret;

    
    switch(cmd)
    {
        case GPIO_CONFIG:
        {
            void __user *ptr = (void __user *)arg;
            ret = copy_from_user( (void*)&gpio_cfg, ptr, sizeof(gpio_cfg) );

            sprintf(gpio_name, "GPIO%c%d", 'A' + gpio_cfg.gpio_no/32, 
                                gpio_cfg.gpio_no%32);

            printk(KERN_INFO "gpio num: %s mode:%s\n", gpio_name,
                        gpio_cfg.gpio_mode == GPIO_MODE_INPUT ? "INPUT" : "OUTPUT");

            if (gpio_cfg.gpio_mode == GPIO_MODE_INPUT)
            {
                gpio_direction_input(gpio_cfg.gpio_no);
            }
            else
            {
                gpio_direction_output(gpio_cfg.gpio_no, gpio_cfg.init_value);
            }
            break;
        }
        case GPIO_SET_VALUE:
        {
            void __user *ptr = (void __user *)arg;
            ret = copy_from_user( (void*)&gpio_value, ptr, sizeof(gpio_value) );

    
            sprintf(gpio_name, "GPIO%c%d", 'A' + gpio_value.gpio_no/32, 
                                            gpio_value.gpio_no%32);
            
            printk(KERN_INFO "SET %s -> %d\n", 
                gpio_name, gpio_value.gpio_value);

            __gpio_set_value( gpio_value.gpio_no, gpio_value.gpio_value);
            break;
        
        }

        case GPIO_GET_VALUE:
        {
            void __user *ptr = (void __user *)arg;
            ret = copy_from_user( (void*)&gpio_value, ptr, sizeof(gpio_value) );
            
            gpio_value.gpio_value = __gpio_get_value(gpio_value.gpio_no);


            sprintf(gpio_name, "GPIO%c%d", 'A' + gpio_value.gpio_no/32, 
                                            gpio_value.gpio_no%32);
            
            printk(KERN_INFO "GET %s's state is %d\n", 
                gpio_name, gpio_value.gpio_value);

            ret = copy_to_user(ptr, (void*)&gpio_value, sizeof(gpio_value));
            break;
        }
    

        default:
            break;
    }


    return 0;
}


static struct file_operations gec6818_gpio_ops =
{
    .unlocked_ioctl = gec6818_gpio_ioctl
};

static struct miscdevice gec_misc = 
{
    .minor = MISC_DYNAMIC_MINOR,
    .name = "gec6818_gpios",  // /dev/gec6818_gpios
    .fops = &gec6818_gpio_ops //文件操作

};


static int __init gec6818_gpio_drv_init(void)
{
    return misc_register(&gec_misc);
}
static void __exit gec6818_gpio_drv_exit(void)
{
    misc_deregister(&gec_misc);
}

module_init(gec6818_gpio_drv_init);
module_exit(gec6818_gpio_drv_exit);

#include <linux/module.h>
#include <linux/vermagic.h>
#include <linux/compiler.h>

MODULE_INFO(vermagic, VERMAGIC_STRING);

struct module __this_module
__attribute__((section(".gnu.linkonce.this_module"))) = {
 .name = KBUILD_MODNAME,
 .init = init_module,
#ifdef CONFIG_MODULE_UNLOAD
 .exit = cleanup_module,
#endif
 .arch = MODULE_ARCH_INIT,
};

static const char __module_depends[]
__used
__attribute__((section(".modinfo"))) =
"depends=";

猜你喜欢

转载自blog.csdn.net/qq_53336580/article/details/122512826
今日推荐