四、通过Socket实现跟AGV小车通信(仅做Demo演示,跟实际工厂运行无关)

在通常情况下AGV的开发是使用PLC或者单片机,我们会使用MOXA等串口服务器配置485或者232通信。
我们会将AGV的MOXA设备配置成服务端。我们按照一定的数据协议从PLC或者单片机获得AGV的信息。

今天我抛开这些协议,通过工具模拟实现openTCS的Socket通信。
我这边用winform写了一个简单的Socket服务端工具(超简单那种)
在这里插入图片描述

我们的代码是基于第一篇文章的,具体参照 https://blog.csdn.net/jielounlee/article/details/85985715

那接下来,我们来具体操作一下
一、在地图上设置AGV的IP地址与端口号
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
每辆小车都要加上IP和Port。我这儿就将其他车辆删掉了,然后保存一下

二、在第一篇文章的TestCommAdapter中写上具体通信
我们首先写一个Socket工具类
在这里插入图片描述

package org.opentcs.testvehicle;

import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;

/**
 *
 * @author zjw
 */
public class SocketUtils {
    private String ip;
  private int port;

  public SocketUtils(String ip, int port) {
    this.ip = ip;
    this.port = port;
  }

  public SocketUtils(String ip, String port) {
    this.ip = ip;
    try {
      this.port = Integer.parseInt(port);
    }
    catch (Exception ex) {
      this.port = 4001;
    }
  }

  public String send(String msg) {
    Socket socket = null;
    String ret = "";
    try {
      socket = new Socket(ip, port);
      socket.setSoTimeout(1000);
      OutputStream out = socket.getOutputStream();
      out.write(msg.getBytes());
      InputStream in = socket.getInputStream();
      byte[] buf = new byte[4096];
      int len = in.read(buf);
      ret = new String(buf, 0, len);
      out.close();
      in.close();
      socket.close();
      return ret;
    }
    catch (Exception ex) {
      try {
        socket.close();
      }
      catch (Exception e) {
      }
      return "";
    }
    finally {
      try {
        socket.close();
      }
      catch (Exception e) {
      }
    }

  }

  public byte[] send(byte[] bytes) {
    Socket socket = null;
    try {
      socket = new Socket(ip, port);
      socket.setSoTimeout(500);
      OutputStream out = socket.getOutputStream();
      out.write(bytes);
      InputStream in = socket.getInputStream();
      byte[] buf = new byte[8];
      int len = in.read(buf);
      out.close();
      in.close();
      socket.close();
      return buf;
    }
    catch (Exception ex) {
      try {
        socket.close();
      }
      catch (Exception e) {
      }
      return null;
    }
    finally {
      try {
        socket.close();
      }
      catch (Exception e) {
      }
    }
  }
}

在TestCommAdapter的构造方法中实例化SocketUtils
在这里插入图片描述
在选择AGV适配器的时候会获取AGV的位置,显示在画面上,开启线程
在这里插入图片描述
停用的时候将线程也停止了
在这里插入图片描述
接下来就是在线程中处理逻辑了
我这边比较简单,仅仅只是模拟了获取状态以及移动操作。

具体完整Adapter代码如下:

package org.opentcs.testvehicle;

import com.google.inject.assistedinject.Assisted;
import java.util.List;
import static java.util.Objects.requireNonNull;
import javax.inject.Inject;
import org.opentcs.data.model.Vehicle;
import org.opentcs.data.order.Route.Step;
import org.opentcs.drivers.vehicle.BasicVehicleCommAdapter;
import org.opentcs.drivers.vehicle.MovementCommand;
import org.opentcs.util.CyclicTask;
import org.opentcs.util.ExplainedBoolean;
import org.opentcs.data.model.Vehicle.Orientation;

/**
 *
 * @author zjw
 */
public class TestCommAdapter extends BasicVehicleCommAdapter {

  private final SocketUtils socketUtils;
  private TestAdapterComponentsFactory componentsFactory;
  private Vehicle vehicle;
  private boolean initialized;
  private CyclicTask testTask;

  @Inject
  public TestCommAdapter(TestAdapterComponentsFactory componentsFactory, @Assisted Vehicle vehicle) {
    super(new TestVehicleModel(vehicle), 2, 1, "CHARGE");
    this.componentsFactory = componentsFactory;
    this.vehicle = vehicle;
    String ip = vehicle.getProperty("IP");
    String port = vehicle.getProperty("Port");
    this.socketUtils = new SocketUtils(ip, port);
  }

  @Override
  public void initialize() {
    initialized = true;
    //网络通信,获取当前位置,电量,等信息
    //getProcessModel().setVehicleState(Vehicle.State.IDLE);
    //getProcessModel().setVehiclePosition("Point-0001");
  }

  @Override
  public synchronized void enable() {
    if (isEnabled()) {
      return;
    }
    //开启线程(略)
    testTask = new TestTask();
    Thread simThread = new Thread(testTask, getName() + "-Task");
    simThread.start();
    super.enable();
  }

  @Override
  public synchronized void disable() {
    if (!isEnabled()) {
      return;
    }
    //线程停止
    testTask.terminate();
    testTask = null;
    super.disable();
  }

  @Override
  public void sendCommand(MovementCommand cmd)
      throws IllegalArgumentException {
    requireNonNull(cmd, "cmd");
  }

  @Override
  public ExplainedBoolean canProcess(List<String> operations) {
    requireNonNull(operations, "operations");

    final boolean canProcess = isEnabled();
    final String reason = canProcess ? "" : "adapter not enabled";
    return new ExplainedBoolean(canProcess, reason);
  }

  @Override
  public void processMessage(Object message) {
  }

  @Override
  protected void connectVehicle() {

  }

  @Override
  protected void disconnectVehicle() {

  }

  @Override
  protected boolean isVehicleConnected() {
    return true;
  }

  /**
   * 内部类,用于处理运行步骤
   */
  private class TestTask
      extends CyclicTask {

    private TestTask() {
      super(0);
    }

    //线程执行
    @Override
    protected void runActualTask() {
      try {
        //获取状态  位置  速度  方向等
        String str = socketUtils.send("{"cmd":"Read","pathFrom":"","pathTo":""}");
        if (str == null) {
          Thread.sleep(1000);
          return;
        }
        if (!str.contains(";")) {
          Thread.sleep(1000);
          return;
        }
        String currentPoint = str.split(";")[0];
        String currentStatus = str.split(";")[1];
        getProcessModel().setVehiclePosition(currentPoint);
        if (currentStatus.equals("free")) {
          getProcessModel().setVehicleState(Vehicle.State.IDLE);
        }
        else if (currentStatus.equals("executing")) {
          getProcessModel().setVehicleState(Vehicle.State.EXECUTING);
        }
        
        
        final MovementCommand curCommand;
        synchronized (TestCommAdapter.this) {
          curCommand = getSentQueue().peek();
        }
        if (curCommand == null) {
         Thread.sleep(1000);
          return;
        }
        final Step curStep = curCommand.getStep();
        simulateMovement(curStep);
        if (!curCommand.isWithoutOperation()) {
          simulateOperation(curCommand.getOperation());
        }
        if (isTerminated()) {
          Thread.sleep(1000);
          return;
        }
        if (getSentQueue().size() <= 1 && getCommandQueue().isEmpty()) {
          getProcessModel().setVehicleState(Vehicle.State.IDLE);
        }
        synchronized (TestCommAdapter.this) {
          MovementCommand sentCmd = getSentQueue().poll();
          if (sentCmd != null && sentCmd.equals(curCommand)) {
            getProcessModel().commandExecuted(curCommand);
            TestCommAdapter.this.notify();
          }
        }
        Thread.sleep(1000);
      }
      catch (Exception ex) {

      }
    }
    
     private void simulateMovement(Step step) throws Exception{
      if (step.getPath() == null) {
        return;
      }
      Orientation orientation = step.getVehicleOrientation();
      long pathLength = step.getPath().getLength();
      int maxVelocity;
      switch (orientation) {
        case BACKWARD:
          maxVelocity = step.getPath().getMaxReverseVelocity();
          break;
        default:
          maxVelocity = step.getPath().getMaxVelocity();
          break;
      }
      String pointName = step.getDestinationPoint().getName();
      getProcessModel().setVehicleState(Vehicle.State.EXECUTING);
      String currentPoint = "";
      String currentStatus = "";
      boolean flag = false;
      while (!flag) {
        String str = socketUtils.send("{"cmd":"Path","pathFrom":"" + currentPoint + "","pathTo":"" + pointName + ""}");
        if (str.equals("OK")) {
          flag = true;
        }
        Thread.sleep(1000);
      }

      while (!currentPoint.equals(pointName) && !isTerminated()) {
        String str = socketUtils.send("{"cmd":"Read","pathFrom":"","pathTo":""}");
        if (str == null) {
          Thread.sleep(1000);
          continue;
        }
        if (!str.contains(";")) {
          Thread.sleep(1000);
          continue;
        }
        currentPoint = str.split(";")[0];
        currentStatus = str.split(";")[1];
        getProcessModel().setVehiclePosition(currentPoint);
        if (currentStatus.equals("free")) {
          getProcessModel().setVehicleState(Vehicle.State.IDLE);
        }
        else if (currentStatus.equals("executing")) {
          getProcessModel().setVehicleState(Vehicle.State.EXECUTING);
        }
      }
    }

    private void simulateOperation(String operation) throws Exception{
      requireNonNull(operation, "operation");
      if (isTerminated()) {
        return;
      }
//      getProcessModel().setVehicleState(Vehicle.State.EXECUTING);
//      if (operation.equals(getProcessModel().getLoadOperation())) {
//        //getProcessModel().setVehicleLoadHandlingDevices(Arrays.asList(new LoadHandlingDevice(LHD_NAME, true)));
//      }
//      else if (operation.equals(getProcessModel().getUnloadOperation())) {
//        //getProcessModel().setVehicleLoadHandlingDevices(Arrays.asList(new LoadHandlingDevice(LHD_NAME, false)));
//      }
    }
  }
}



附件:AGV模拟工具
链接:https://pan.baidu.com/s/1VgupmQKX0sQvIdzQQ63Q8Q
提取码:n2e8

原文地址:https://www.cnblogs.com/zjwno1/p/13097327.html