linux+cpp,串口转usb,控制失灵

省流:python脚本调用正常,写了个python脚本再用cpp调用


具体来说,使用的是wheeltech轮趣家的二自由度云台,串口转usb,里头应该是rs485,驱动用ch340,板子说是stm32、用商家的自带控制程序。用第一款云台(他家的内部名字大概是模块化款)cpp和python都没啥问题,用第二款云台(他家内部名字大概是c06款)python能用cpp就不行了。二者使用ubuntu的串口助手cutecom表现相同。分享代码如下,有差别的自行调整:

cpp部分(set_opt,_System函数也是网上抄的,出处懒得找了,大概也是csdn)(changedegree函数是原始的cpp直接控制,changedegree2函数是调用python脚本):

#include <errno.h>
#include <fcntl.h>
#include <iostream>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <string>
#include <sys/select.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#include <termios.h>
#include <unistd.h>

using namespace std;

float YY = 1960;
float pantiltRotatingCenterHeight = 2060;
int set_opt(int fd, int nSpeed, int nBits, char nEvent, int nStop)
{
    struct termios newtio, oldtio;
    if (tcgetattr(fd, &oldtio) != 0) {
        perror("SetupSerial 1");
        return -1;
    }
    bzero(&newtio, sizeof(newtio));
    newtio.c_cflag |= CLOCAL | CREAD;
    newtio.c_cflag &= ~CSIZE;

    switch (nBits) {
    case 7:
        newtio.c_cflag |= CS7;
        break;
    case 8:
        newtio.c_cflag |= CS8;
        break;
    }

    switch (nEvent) {
    case 'O': // ji
        newtio.c_cflag |= PARENB;
        newtio.c_cflag |= PARODD;
        newtio.c_cflag |= (INPCK | ISTRIP);
        break;
    case 'E': // ou
        newtio.c_cflag |= PARENB;
        newtio.c_cflag |= ~PARODD;
        newtio.c_cflag |= (INPCK | ISTRIP);
        break;
    case 'N': // no
        newtio.c_cflag |= ~PARENB;
        break;
    }

    switch (nSpeed) {
    case 2400:
        cfsetispeed(&newtio, B2400);
        cfsetospeed(&newtio, B2400);
        break;
    case 4800:
        cfsetispeed(&newtio, B4800);
        cfsetospeed(&newtio, B4800);
        break;
    case 9600:
        cfsetispeed(&newtio, B9600);
        cfsetospeed(&newtio, B9600);
        break;
    case 115200:
        cfsetispeed(&newtio, B115200);
        cfsetospeed(&newtio, B115200);
        break;
    default:
        cfsetispeed(&newtio, B9600);
        cfsetospeed(&newtio, B9600);
        break;
    }
    if (nStop == 1)
        newtio.c_cflag &= ~CSTOPB;
    else if (nStop == 2)
        newtio.c_cflag &= CSTOPB;
    newtio.c_cc[VTIME] = 0;
    newtio.c_cc[VMIN] = 0;
    tcflush(fd, TCSANOW);
    if ((tcsetattr(fd, TCSANOW, &newtio) != 0)) {
        perror("com set error");
        return -1;
    }
    printf("set done!\n");
    return 0;
}

int _System(const char* cmd, char* pRetMsg, int msg_len)
{
    FILE* fp;
    int res = -1;
    if (cmd == NULL || pRetMsg == NULL || msg_len < 0) {
        printf("Param Error!\n");
        return -1;
    }
    if ((fp = popen(cmd, "r")) == NULL) {
        printf("Popen Error!\n");
        return -2;
    } else {
        memset(pRetMsg, 0, msg_len);
        // get lastest result
        while (fgets(pRetMsg, msg_len, fp) != NULL) {
            // printf("Msg:%s",pRetMsg); //print all info
        }

        if ((res = pclose(fp)) == -1) {
            printf("close popenerror!\n");
            return -3;
        }
        pRetMsg[strlen(pRetMsg) - 1] = '\0';
        return 0;
    }
}
// cmd num range:8~180
// real num:40——down 45 degrees, 120——up 4 degrees
// camera num:82(down 60),-90(up 42)
inline float pantiltNum2DownDegree(short num) { return 45 - 49.0 / 80.0 * (num - 40); }
short oriNum = 70;

float changeDegree2(short newNum)
{
    short NumMaxLimit = 180;
    short NumMinLimit = 0;
    float radius = 52.0f + 26.0f / 2; // 5.2cm: pantilt rorating radius, 2.6cm: camara height
    float extendingPartLength = 125.4f - 63.4f - 5.0f; // approximate distance from hinge point to depth camera
    float newDownDegree = pantiltNum2DownDegree(newNum);

    if (newNum > NumMaxLimit) {
        return pantiltNum2DownDegree(NumMaxLimit);
    }
    if (newNum < NumMinLimit) {
        return pantiltNum2DownDegree(NumMinLimit);
    }
    char tmp[256] = { 0 };
    string cmd1 = "ls /dev|grep USB";
    if (_System(cmd1.c_str(), tmp, sizeof(tmp)) != 0) {
        exit(-1);
    }
    string uartPath = "/dev/" + string(tmp);
    cout << uartPath << endl;

    char newNum_str[256];
    sprintf(newNum_str, "%d", newNum);

    string cmd2 = "python3 gimbal.py " + string(newNum_str) + " " + string(tmp);
    cout << cmd2 << endl;
    char tmp2[256] = { 0 };
    if (_System(cmd2.c_str(), tmp2, sizeof(tmp2)) != 0) {
        exit(-1);
    }

    YY = pantiltRotatingCenterHeight - radius * cos(newDownDegree) - extendingPartLength * sin(newDownDegree);

    return newDownDegree;
}

float changeDegree(short newNum)
{
    short NumMaxLimit = 180;
    short NumMinLimit = 0;
    float radius = 52.0f + 26.0f / 2; // 5.2cm: pantilt rorating radius, 2.6cm: camara height
    float extendingPartLength = 125.4f - 63.4f - 5.0f; // approximate distance from hinge point to depth camera
    float newDownDegree = pantiltNum2DownDegree(newNum);

    if (newNum > NumMaxLimit) {
        return pantiltNum2DownDegree(NumMaxLimit);
    }
    if (newNum < NumMinLimit) {
        return pantiltNum2DownDegree(NumMinLimit);
    }
    unsigned char cmd[] = { 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
    cmd[3] = cmd[9] = newNum;

    char tmp[256] = { 0 };
    string cmd1 = "ls /dev|grep USB";
    if (_System(cmd1.c_str(), tmp, sizeof(tmp)) != 0) {
        exit(-1);
    }
    string uartPath = "/dev/" + string(tmp);
    cout << uartPath << endl;
    int fd = 1;

    if ((fd = open(uartPath.c_str(), O_RDWR | O_NOCTTY | O_NDELAY)) < 0) {
        printf("open %s is failed\n", uartPath.c_str());
        exit(-1);
    } else {
        set_opt(fd, 115200, 8, 'N', 1);
        write(fd, cmd, 10);
        close(fd);
    }
    YY = pantiltRotatingCenterHeight - radius * cos(newDownDegree) - extendingPartLength * sin(newDownDegree);

    return newDownDegree;
}
int main(int argc, char* argv[])
{
    if (argc == 2) {
        oriNum = atoi(argv[1]);
    }
    float a = changeDegree2(oriNum);
    cout << "num:" << oriNum << ", down degree:" << a << ", YY:" << YY << ", rotating height:" << pantiltRotatingCenterHeight << endl;
}

python部分(设置十次写入或者读取云台回复的部分是和云台本身有关的,参考可以不看)(运行之前pip3 install pyserial装一下依赖库):

import serial,sys
send_limit=10

a=int(sys.argv[1])
b=hex(a)[2:]
cmd="FFFE00"+b+"0000000000"+b
uart=sys.argv[2]

print(a,b,cmd,uart)
cmd_b=bytes.fromhex(cmd)
ser = serial.Serial('/dev/'+uart, 115200, bytesize=8, stopbits=1, parity='N',timeout=1)

for i in range(send_limit):

    ser.write(cmd_b)
    ret=ser.read(80)
    try:
        ret_str=str(ret, encoding='gbk', errors='ignore')
    except:
        print(ret)
        ret_str=str(ret[1:], encoding='gbk', errors='ignore')
    ok=False
    for line in ret_str.split():
        if line == "舵机B角度:"+str(a):
            ok=True
    if ok:break
    else:
        print(f"send try {i} failed!{ret_str.split()}")

ser.close()

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值