Python串口通信Arduino

最近在做一个小项目,希望实现的功能是:

在PC端跑deepsort等目标识别代码,然后返回目标在视频中的坐标(x,y)。将检测量(x,y)传入PID中得到执行量(do_x,do_y)。这个时候我们遇到了一个问题,如何使用python代码调用串口,并且正确传递(do_x,do_y)给单片机(arduino)。

查了很多资料,发现要么就是只传递单个数字字符串,要么代码不适用arduino端。我写了一个简单的算法,具体原理是:

python端代码

  1. 获得do_x,do_y(代码中变量名为x,y)。将两个int型变量转换为字符串str_x,str_y

    python中的传递函数write(),传递的是字节流。因此我们先要将int数字转换为字符串。之后,通过encode()转换为字节流

    x_str = str(x)
    y_str = str(y)
    
  2. 构造传递字符串,设置头和尾

    为了保证传递的x和y是一组的,我设置了传递数据的头和尾:

    start = "b"
    end = "e"
    x = 1500
    x_str = str(x)
    y = 1300
    y_str = str(y)
    dot = ","
    str1 = start + x_str + dot + y_str + end
    

    此时str1就是我们需要传递的变量

  3. 完整代码

    代码效果是不断传递(x = 1500,y = 1300)和(x = 1300,y = 1500)。最终让舵机循环往复的在两个角度位置运动

    # coding:utf-8
    import serial.tools.list_ports
    import time
    import struct
    
    plist = list(serial.tools.list_ports.comports())# plist 包含的是还有串口一维数组 comports()是返回一串串口对象,这些对象包含三个变量:port name, human readable description and a hardware ID
    
    if len(plist) <= 0: # 在我的电脑上 len(plist)是4
            print("没有发现端口!")
    else:
            plist_0 = list(plist[4])# 定义plist[4]三个变量的lsit
            serialName = plist_0[0]# 取出其中的端口名
            serialFd = serial.Serial(serialName, 9600, timeout=60)# timeout单位是秒,设置后,如果没有设置回读的判断条件,就会一直等到timeout后打出返回结果。
            print("可用端口名>>>", serialFd.name)
    while 1:
            start = "b"
            end = "e"
            x = 1500
            x_str = str(x)
            y = 1300
            y_str = str(y)
            dot = ","
            str1 = start + x_str + dot + y_str + end
            serialFd.write(str1.encode())# encode()完成的是对原字符串进行编码
            time.sleep(0.5)
    
            x = 1300
            x_str = str(x)
            y = 1500
            y_str = str(y)
            str1 = start + x_str + dot + y_str + end
            serialFd.write(str1.encode())# encode()完成的是对原字符串进行编码
            time.sleep(0.5)
    

    arduino端代码

    /*******************************************************************************             
      * @库文件: <Servo.h>
      * @功能:   实现串口接收500-2500PWM值实现舵机控制
     ******************************************************************************/
    /*----------------------------------------------------------------------------
        相关库函数:
        1.servo类成员函数
        attach()              设定舵机的接口,只有9或10接口可利用。
        write()               用于设定舵机旋转角度的语句,可设定的角度范围是0°到180°。
        writeMicroseconds()  用于设定舵机PWM值的语句,直接用微秒作为参数。
        read()                用于读取舵机角度的语句,可理解为读取最后一条write()命令中的值。
        attached()            判断舵机参数是否已发送到舵机所在接口。
        detach()              使舵机与其接口分离,该接口(9或10)可继续被用作PWM接口。12
      ----------------------------------------------------------------------------*/
    #include <Servo.h>                // 声明调用Servo.h库
    #include <SoftwareSerial.h>//引用串口
    Servo myservo_y;                    //竖直方向舵机类
    Servo myservo_x;                     //水平方向舵机类
    String inStringx = "";             //声明一个字符串
    String inStringy = "";             //声明一个字符串
    String comdata = "";               //声明一个字符串
    #define  PIN_x  7 //           //宏定义舵机控制引脚
    #define  PIN_y  A1 //           //宏定义舵机控制引脚
    int x = 0,y = 0;
    
    void receive(){
      int tmp = 0;//用于记录逗号所在的位置
      int j = 0;//用于记录是x数据还是y数据。0是x数据,1是y数据
      // 先将一次通信中的字节流数据读入,并将其拼接成字符串
      // comdata的头是字符'b',尾是字符'e'。
      while(Serial.available()>0)
      {
        comdata += char(Serial.read());
        delay(2);
        if(comdata[comdata.length()-1] == 'e')break;
      }
      
      Serial.println(comdata);
      // 对读入的数据comdata进行翻译,获取包含的x和y数据  
      if(comdata[0] == 'b')
      {
        for(int i = 1; i<comdata.length();i++)
        {
          if(comdata[i]==',')
          {
            tmp = i;
            j++;
            continue;
          }
          else if(j==0)
          {
            
            inStringx += comdata[i];
          }
          else
          {
            if(i==comdata.length()-1)
              continue; // 此时到达最后一位,也就是e
            else
              inStringy += comdata[i];
          }
        }
      }
      j = 0;
      tmp = 0;
      comdata = "";
      // 将获得包含有数据的字符串 inStringx 和 inStringy 转换成整型变量。
      if(inStringx.length()>0 && inStringy.length()>0)
      {
        x = inStringx.toInt();
        Serial.println(inStringx);
        y = inStringy.toInt();
        Serial.println(inStringy);
        myservo_x.writeMicroseconds(x); // 控制水平方向舵机运动
        delay(2);
        myservo_y.writeMicroseconds(y); // 控制垂直方向舵机运动
        delay(2);
        inStringx = "";
        inStringy = "";
    
      }
    
    }
    
    void setup(){ 
        myservo_x.attach(PIN_x);    // 将引脚与声明的舵机对象连接起来
        myservo_y.attach(PIN_y);    // 将引脚与声明的舵机对象连接起来
        Serial.begin(9600);        //初始化波特率为9600
        myservo_x.writeMicroseconds(1500); // 初始化舵机位置
        myservo_y.writeMicroseconds(1500); // 初始化舵机位置
    
    } 
    
    void loop(){
      while(Serial.available())
      {
        receive();
      }
    }
    
  • 14
    点赞
  • 54
    收藏
    觉得还不错? 一键收藏
  • 7
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值