松灵机器人TRACER 操控心得

松灵机器人TRACER 串口232 操控

最近公司项目有一个控制松灵机器人的东西 ,把心得给大家说一下
在这里插入图片描述

根据松灵今日官网文档中的操作中关于 串口通讯的论述如图

在这里插入图片描述

机器人中有一个232 的串口 可以转usp 接口 然后可以通过电脑用串口通过串口机器人

java 控制串口发送指令

public class ParamConfig {
	/****
	***这是设置串口连接参数配置
	**/
    private String serialNumber;// 串口号
    private int baudRate;        // 波特率
    private int checkoutBit;    // 校验位
    private int dataBit;        // 数据位
    private int stopBit;        // 停止位
    
    public ParamConfig(String[] args, int baudRate, int checkoutBit, int dataBit, int stopBit) {}
        
    /**
     * 构造方法
     * @param serialNumber    串口号
     * @param baudRate        波特率
     * @param checkoutBit    校验位
     * @param dataBit        数据位
     * @param stopBit        停止位
     */
    public ParamConfig(String serialNumber, int baudRate, int checkoutBit, int dataBit, int stopBit) {
        this.serialNumber = serialNumber;
        this.baudRate = baudRate;
        this.checkoutBit = checkoutBit;
        this.dataBit = dataBit;
        this.stopBit = stopBit;
    }

	public String getSerialNumber() {
		return serialNumber;
	}

	public void setSerialNumber(String serialNumber) {
		this.serialNumber = serialNumber;
	}

	public int getBaudRate() {
		return baudRate;
	}

	public void setBaudRate(int baudRate) {
		this.baudRate = baudRate;
	}

	public int getCheckoutBit() {
		return checkoutBit;
	}

	public void setCheckoutBit(int checkoutBit) {
		this.checkoutBit = checkoutBit;
	}

	public int getDataBit() {
		return dataBit;
	}

	public void setDataBit(int dataBit) {
		this.dataBit = dataBit;
	}

	public int getStopBit() {
		return stopBit;
	}

	public void setStopBit(int stopBit) {
		this.stopBit = stopBit;
	}

 
}

这是发送指令接收指令的代码

public class SendUtil {

	private static final String SEND_LEN_ERROR_MSG = "封装参数格式错误";
	private static final String HYSTRIX_ERROR_MSG = "Hystrix:";

	/**
	 * @param objs
	 * @return Map<String, Object>
	 * @throws
	 * @Title: send
	 * @Description: 返回封装
	 */
	public static Map<String, Object> send(Object... objs) {
		Map<String, Object> params = new HashMap<>(3);
		if (objs.length == 0 || objs.length > 3) {
			params.put("result", false);
			params.put("msg", SEND_LEN_ERROR_MSG);
			params.put("data", "");
		} else {
			params.put("result", objs[0] != null ? objs[0] : false);
			params.put("msg", objs.length > 1 && objs[1] != null ? objs[1] : "");
			params.put("data", objs.length > 2 && objs[2] != null ? objs[2] : "");
		}
		return params;
	}


	/**
	 * @param hystrixMsg
	 * @return
	 * @Title: hystrix
	 * @Description: 熔断器返回值
	 * @author: YJQ
	 * @date: 2020年8月14日 下午3:08:25
	 * @returnType Map<String, Object>
	 */
	public static Map<String, Object> hystrix(String hystrixMsg) {
		Map<String, Object> params = new HashMap<>(3);
		params.put("result", false);
		params.put("msg", HYSTRIX_ERROR_MSG + hystrixMsg);
		params.put("data", null);
		return params;
	}

	public static Map<String, Object> sendCode(Object... objs) {
		Map<String, Object> params = new HashMap<>(3);

		if (objs.length == 0 || objs.length > 4) {
			params.put("result", false);
			params.put("msg", SEND_LEN_ERROR_MSG);
			params.put("data", "");
		} else {
			params.put("result", objs[0] != null ? objs[0] : false);
			params.put("code", objs.length > 2 && objs[1] != null ? objs[1] : "");
			params.put("msg", objs.length > 1 && objs[2] != null ? objs[2] : "");
			params.put("data", objs.length > 3 && objs[3] != null ? objs[3] : "");
		}
		return params;
	}


	/**
	 * 返回 Layui 表格格式的数据
	 *
	 * @param count
	 * @param data
	 * @return
	 */
	public static Map<String, Object> layuiTable(long count, Object data) {
		Map<String, Object> msg = new HashMap<>();
		msg.put("code", 0);
		msg.put("msg", ConstString.RESULT_SUCCESS);
		msg.put("count", count);
		msg.put("data", data);
		return msg;
	}


}


/**
 * -**串口参数的配置 串口一般有如下参数可以在该串口打开以前进行配置: 包括串口号,波特率,输入/输出流控制,数据位数,停止位和奇偶校验。
 */
// 注:串口操作类一定要继承SerialPortEventListener
public class SerialPortUtils implements SerialPortEventListener {
    // 检测系统中可用的通讯端口类
    private CommPortIdentifier commPortId;
    // 枚举类型
    private Enumeration<CommPortIdentifier> portList;
    // RS232串口
    private SerialPort serialPort;
    // 输入流
    private InputStream inputStream;
    // 输出流
    private OutputStream outputStream;
    // 保存串口返回信息
    private String data;
    // 保存串口返回信息十六进制
    private String dataHex;


    /**
     * @throws Exception 
     * 初始化串口
     * @author 
     * @date 2018年7月21日下午3:44:16
     * @Description: TODO
     * @param: paramConfig  存放串口连接必要参数的对象(会在下方给出类代码)    
     * @return: void      
     * @throws
     */
    @SuppressWarnings("unchecked")
    public void init(ParamConfig paramConfig) throws Exception {
        // 获取系统中所有的通讯端口
        portList = CommPortIdentifier.getPortIdentifiers();
        // 记录是否含有指定串口
        boolean isExsist = false;
        // 循环通讯端口
        while (portList.hasMoreElements()) {
            commPortId = portList.nextElement();
            // 判断是否是串口
            if (commPortId.getPortType() == CommPortIdentifier.PORT_SERIAL) {
                // 比较串口名称是否是指定串口
                if (paramConfig.getSerialNumber().equals(commPortId.getName())) {
                    // 串口存在
                    isExsist = true;
                    // 打开串口
                    try {
                        // open:(应用程序名【随意命名】,阻塞时等待的毫秒数)
                        serialPort = (SerialPort) commPortId.open(Object.class.getSimpleName(), 2000);
                        // 设置串口监听
                        serialPort.addEventListener(this);
                        // 设置串口数据时间有效(可监听)
                        serialPort.notifyOnDataAvailable(true);
                        // 设置串口通讯参数:波特率,数据位,停止位,校验方式
                        serialPort.setSerialPortParams(paramConfig.getBaudRate(), paramConfig.getDataBit(),
                                paramConfig.getStopBit(), paramConfig.getCheckoutBit());
                    } catch (PortInUseException e) {
                        throw new Exception("端口被占用");
                    } catch (TooManyListenersException e) {
                        throw new Exception("监听器过多");
                    } catch (UnsupportedCommOperationException e) {
                        throw new Exception("不支持的COMM端口操作异常");
                    }
                    // 结束循环
                    break;
                }
            }
        }
        // 若不存在该串口则抛出异常
        if (!isExsist) {
            throw new Exception("不存在该串口!");
        }
    }

    /**
     * 实现接口SerialPortEventListener中的方法 读取从串口中接收的数据
     */
    @Override
    public void serialEvent(SerialPortEvent event) {
        switch (event.getEventType()) {
        case SerialPortEvent.BI: // 通讯中断
        case SerialPortEvent.OE: // 溢位错误
        case SerialPortEvent.FE: // 帧错误
        case SerialPortEvent.PE: // 奇偶校验错误
        case SerialPortEvent.CD: // 载波检测
        case SerialPortEvent.CTS: // 清除发送
        case SerialPortEvent.DSR: // 数据设备准备好
        case SerialPortEvent.RI: // 响铃侦测
        case SerialPortEvent.OUTPUT_BUFFER_EMPTY: // 输出缓冲区已清空
            break;
        case SerialPortEvent.DATA_AVAILABLE: // 有数据到达
            // 调用读取数据的方法
            try {
				readComm();
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
            break;
        default:
            break;
        }
    }

    /**
     * 读取串口返回信息
     * @author LinWenLi
     * @date 2018年7月21日下午3:43:04
     * @return: void      
     * @throws Exception 
     */
    public void readComm() throws Exception {
        try {
            inputStream = serialPort.getInputStream();
            // 通过输入流对象的available方法获取数组字节长度
            byte[] readBuffer = new byte[inputStream.available()];
            // 从线路上读取数据流
            int len = 0;
            while ((len = inputStream.read(readBuffer)) != -1) {
                data = new String(readBuffer, 0, len).trim();
                dataHex = bytesToHexString(readBuffer);
               // System.out.println("data:" + data);
//                System.out.println("dataHex:" + dataHex);// 读取后置空流对象
                inputStream.close();
                inputStream = null;
                break;
            }
        } catch (IOException e) {
            throw new Exception("读取串口数据时发生IO异常");
        }
    }

    /**
     * @throws Exception 
     * 发送信息到串口
     * @author LinWenLi
     * @date 2018年7月21日下午3:45:22
     * @param: data      
     * @return: void      
     * @throws
     */
    public void sendComm(String data) throws Exception {
        byte[] writerBuffer = null;
        try {
            writerBuffer = hexToByteArray(data);
        } catch (NumberFormatException e) {
            throw new Exception("命令格式错误!");
        }
        try {
            outputStream = serialPort.getOutputStream();
            outputStream.write(writerBuffer);
            outputStream.flush();
        } catch (NullPointerException e) {
            throw new Exception("找不到串口。");
        } catch (IOException e) {
            throw new Exception("发送信息到串口时发生IO异常");
        }
    }

    /**
     * @throws Exception 
     * 关闭串口
     * @author LinWenLi
     * @date 2018年7月21日下午3:45:43
     * @Description: 关闭串口
     * @param:       
     * @return: void      
     * @throws
     */
    public void closeSerialPort() throws Exception {
        if (serialPort != null) {
            serialPort.notifyOnDataAvailable(false);
            serialPort.removeEventListener();
            if (inputStream != null) {
                try {
                    inputStream.close();
                    inputStream = null;
                } catch (IOException e) {
                    throw new Exception("关闭输入流时发生IO异常");
                }
            }
            if (outputStream != null) {
                try {
                    outputStream.close();
                    outputStream = null;
                } catch (IOException e) {
                    throw new Exception("关闭输出流时发生IO异常");
                }
            }
            serialPort.close();
            serialPort = null;
        }
    }

    /**
     * 十六进制串口返回值获取
     */
    public String getDataHex() {
        String result = dataHex;
        // 置空执行结果
        dataHex = null;
        // 返回执行结果
        return result;
    }

    /**
     * 串口返回值获取
     */
    public String getData() {
        String result = data;
        // 置空执行结果
        data = null;
        // 返回执行结果
        return result;
    }

    /**
     * Hex字符串转byte
     * @param inHex 待转换的Hex字符串
     * @return 转换后的byte
     */
    public static byte hexToByte(String inHex) {
        return (byte) Integer.parseInt(inHex, 16);
    }

    /**
     * hex字符串转byte数组
     * @param inHex 待转换的Hex字符串
     * @return 转换后的byte数组结果
     */
    public static byte[] hexToByteArray(String inHex) {
        int hexlen = inHex.length();
        byte[] result;
        if (hexlen % 2 == 1) {
            // 奇数
            hexlen++;
            result = new byte[(hexlen / 2)];
            inHex = "0" + inHex;
        } else {
            // 偶数
            result = new byte[(hexlen / 2)];
        }
        int j = 0;
        for (int i = 0; i < hexlen; i += 2) {
            result[j] = hexToByte(inHex.substring(i, i + 2));
            j++;
        }
        return result;
    }

    /**
     * 数组转换成十六进制字符串
     * @param
     * @return HexString
     */
    public static final String bytesToHexString(byte[] bArray) {
        StringBuffer sb = new StringBuffer(bArray.length);
        String sTemp;
        for (int i = 0; i < bArray.length; i++) {
            sTemp = Integer.toHexString(0xFF & bArray[i]);
            if (sTemp.length() < 2)
                sb.append(0);
            sb.append(sTemp.toUpperCase());
        }
        return sb.toString();
    }
}

这些是控制车机指令代码 可以先用串口调试工具测试 具体的如何控制看官网文档中的运动控制
大概是数据转成unsigned int8 格式的数据 根据具体需求计算,需要基础数学比较的好的同学算,理解低八位,和高八位等等,最后还有一个控制车灯打开关闭的指令代码

//起始位0x5A 0xA5 加帧长度 0x0A令集0x55 + 0x01+控制模式=0x02 和为161

5A A5 0A 55 01 02 01 00 00 00 00 00 62

//低八位转 向左 
5A A5 0A 55 01 02 00 00 00 90 00 00 F1

// 高八位 向右
5A A5 0A 55 01 02 00 00 A0 00 00 00 01
低八位  向左 
5A A5 0A 55 01 02 00 00 00 A0 00 00 01

// 高八位 转数 向右
5A A5 0A 55 01 02 00 00 90 00 00 00 F1

//低位 向右
5A A5 0A 55 01 02 00 00 FF AF 00 00 0F

//高八位 向左
5A A5 0A 55 01 02 01 00 04 00 00 00 66

低八位 向左
 5A A5 0A 55 01 02 00 00 00 90 00 00 F1
// 高八位 转数 向后
5A A5 0A 55 01 02 FC 00 00 00 00 00 5D
//高八位 向右转
5A A5 0A 55 01 02 00 64 A0 00 00 00 65

//低八位转数 向前 
5A A5 0A 55 01 02 00 64 00 00 00 00 C5
// 向前  快一点
5A A5 0A 55 01 02 01 60 00 00 00 00 C2
//低八位向后
5A A5 0A 55 01 02 FF C0 00 00 00 00 20
5A A5 0A 55 01 02 FF A0 00 00 00 00 00
//高八位 向前
5A A5 0A 55 01 02 64 00 00 00 00 00 C5


测试
5A A5 0A 55 01 02 90 00 00 00 00 00 F1



5A A5 0A 55 01 02 00 00 00 0A 00 00 BC


 方向反对
5A A5 0A 55 01 02 00 00 04 00 00 00 65 左
5A A5 0A 55 01 02 00 00 81 90 00 00 72 右
 
5A A5 0A 55 01 02 00 00 FF AF 00 00 0F 右 
5A A5 0A 55 01 02 00 00 00 AF 00 00 10 左

// 高八位 转数 向右
5A A5 0A 55 01 02 00 00 90 00 00 00 F1
线速度加快
5A A5 0A 55 01 02 FF 64 00 00 00 00 C4 后
5A A5 0A 55 01 02 01 60 00 00 00 00 C2 前

5A A5 0A 55 FF 02 01 60 00 00 00 00 0C 



5AA50A550201006400000000C5 车灯熄灭
5AA50A550201016400000000C6  车灯亮

INSERT INTO `aoto_car`.`instruction` (`id`, `instruction`, `direction`, `num`, `delay`) VALUES ('5', '5AA50A550201016400000000C6', '5', '1', '500');
INSERT INTO `aoto_car`.`instruction` (`id`, `instruction`, `direction`, `num`, `delay`) VALUES ('6', '5AA50A550201006400000000C5', '6', '1', '500');

这是导航机器人连接需要的一些驱动文件
链接:https://pan.baidu.com/s/1vD3eB1KCsyUdQoJedtR4og 
提取码:zxc1

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值