遥控小车(基于TCP/IP)

      最后更新:2022-01-16 09:39:40 手机定位技术交流文章

      其实我更想用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:%dn", 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 %sn", 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);

      //连接小车

      voidTCPcar2::on_ctnConnect_clicked()

      {

      //获取IP和端口号

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

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

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

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

      }

      //断开连接

      voidTCPcar2::on_ctnDisconnect_clicked()

      {

      //断开连接

      tcpSocket->disconnectFromHost();

      tcpSocket->close();

      }

      //前进

      voidTCPcar2::on_ctnForward_pressed()

      {

      QString str1="1";

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

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

      //qDebug()<<"1";

      }

      voidTCPcar2::on_ctnForward_released()

      {

      // QString str0="0";

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

      // qDebug()<<"0";

      }

      //后退

      voidTCPcar2::on_ctnBack_pressed()

      {

      QString str2="2";

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

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

      //qDebug()<<"2";

      }

      voidTCPcar2::on_ctnBack_released()

      {

      // QString str0="0";

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

      // qDebug()<<"0";

      }

      //左转

      voidTCPcar2::on_ctnLeft_pressed()

      {

      QString str3="3";

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

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

      //qDebug()<<"3";

      }

      voidTCPcar2::on_ctnLeft_released()

      {

      // QString str0="0";

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

      // qDebug()<<"0";

      }

      // 右转

      voidTCPcar2::on_ctnRight_pressed()

      {

      QString str4="4";

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

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

      //qDebug()<<"4";

      }

      voidTCPcar2::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"));

      //}

      voidTCPcar2::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:%sn", 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 -> %dn",
      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 %dn",
      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=";

      本文由 在线网速测试 整理编辑,转载请注明出处,原文链接:https://www.wangsu123.cn/news/16601.html

          热门文章

          文章分类