zoukankan      html  css  js  c++  java
  • 基于Rayland主板的3D打印机指令控制Android(部分)实现

    本篇以Magicfirm MBotRayland-C200为例介绍基于Rayland主板的FDM打印机指令控制Android端部分实现。

    基于MBot的实现

    Mbot打印机通过RS232串口和Rayland主板进行通信,通过Rayland主板外接屏实现人机交互。

    RS232是全双工串口,所以程序里不需要做特别的处理。(不同于下面Rayland-C200

    需要注意的是,FDM是通过下发Gcode指令进行控制。Mbot中会有一个队列来存储通过串口接收到的Gcode指令,但是存储的指令数量有限。所以在下发的程序中我们需要做容量控制检测队列的剩余容量。

    每条指令执行完成之后Mbot会回传一个callback,我们通过callback来控制队列的剩余容量。

    Android 实现

    综上所述我们需要一个列队,而且是一个阻塞队列,来对指令进行控制。

    发送指令线程不断loop从队列中取出指令并发送给Mbot。当队列为空的时候,发送线程阻塞等待。当队列满的时候存储指令线程阻塞等待。

    由于我们还添加了callback容量控制所以在Mbot队列达到指定余量的时候也会阻塞。这里我们使用Semaphore来实现阻塞。

    看起来是个很完美的流程,但是很多时候我们希望有一些指令能快速的被执行。

    比如说温度检测,设备内温度超过55°C时,我们希望设备能够立即停止(并会有一系列降温等其他额外操作)。而不是排在队尾进行默默等待。

    所以我们就需要一个可以在队头插入的阻塞队列LinkedBlockingDeque

    同时保证Mbot中队列长度为1,执行完当前指令,发送下一条指令。如果存在上述较紧急的情况,将需要插队指令插入队列头。就能较快的响应操作。

    
    public abstract class LoopDeque<T> {
    	
    	private LinkedBlockingDeque<T> commands;
    	private volatile boolean runningLoop;
    	private volatile T current;
    	private Executor executor;
    	
    	public LoopDeque(int capacity){
    		commands = new LinkedBlockingDeque<>(capacity);
    		executor = Executors.newSingleThreadExecutor();
    	}
    
    	public void startLoop() {
    		if(!runningLoop){
    			runningLoop = true;
    			executor.execute(loop);
    		}
    	}
    	
    	public void cancelLoop() {
    		if (runningLoop) {
    			runningLoop = false;
    		}
    	}
    	
    	public void remove(T command){
    		if(command != null && commands.contains(command)){
    			try {
    				commands.take();
    			} catch (InterruptedException e) {
    			}
    		}
    	}
    
    
    	public void add(T object){
    		if(object != null){
    			try {
    				commands.put(object);
    			} catch (InterruptedException e) {
    				e.printStackTrace();
    			}
    		}
    	}
    
      public void insert(T object) {
            if (object != null) {
                try {
                    commands.putFirst(object);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
      
    	public int getSize(){
    		return commands.size();
    	}
    	
    	private Runnable loop = new Runnable() {
    		public void run() {
    			while(runningLoop){
    					try {
    						current = commands.take();
    						if(current!=null){
    							loop(current);
    						}
    					} catch (InterruptedException e) {
    						e.printStackTrace();
    					}
    			}
    		}
    	};
    	
    	public abstract void loop(T object);
    }
    
    

    MainActivity:

    
    
        private volatile boolean isSync;
        /**
         * 通过 Semaphore 控制,保证执行完当前指令发送下一条指令
         * acquire
         */
        private Semaphore semaphore = new Semaphore(0);
    
        queue = new LoopQueue<String>(3) {
                            @Override
                            public void loop(String object) {
                                try {
                                    if(isSync){
                                        semaphore.acquire();
                                    }else{
                                        Thread.sleep(3000);
                                        isSync = true;
                                    }
                                    os.write(object.getBytes());
                                } catch (IOException | InterruptedException e) 
                                    e.printStackTrace();
                                }
                            }
                        };
                    queue.startLoop();
    
    
    ...
    
               /**
                 * callback and release
                 */
     			if (response.contains("ok")) {
                                semaphore.release();
                            }
    
    

    LinkedBlockingDeque

    LinkedBlockingDeque双向链表实现的双向并发阻塞队列,该阻塞队列同时支持FIFOFILO两种操作方式,即可以从队列的头和尾同时操作(插入/删除);并且,该阻塞队列是支持线程安全。

    LinkedBlockingDeque

    LinkedBlockingDeque

    • capacity:LinkedBlockingDeque的容量

    • lock:控制对LinkedBlockingDeque的互斥锁,当多个线程竞争同时访问LinkedBlockingDeque时,某线程获取到了互斥锁lock,其它线程则需要阻塞等待,直到该线程释放lock,其它线程才有机会获取lock从而获取cpu执行权。

    • notEmptynotFull:分别是“非空条件”和“未满条件”。通过它们能够更加细腻进行并发控制。

    • first:表头

    • last:表尾

    • count:LinkedBlockingDeque的实际大小

    -- 若某线程(线程A)要取出数据时,队列正好为空,则该线程会执行notEmpty.await()进行等待;当其它某个线程(线程B)向队列中插入了数据之后,会调用notEmpty.signal()唤醒“notEmpty上的等待线程”。此时,线程A会被唤醒从而得以继续运行。 此外,线程A在执行取操作前,会获取takeLock,在取操作执行完毕再释放takeLock。
    -- 若某线程(线程H)要插入数据时,队列已满,则该线程会它执行notFull.await()进行等待;当其它某个线程(线程I)取出数据之后,会调用notFull.signal()唤醒“notFull上的等待线程”。此时,线程H就会被唤醒从而得以继续运行。 此外,线程H在执行插入操作前,会获取putLock,在插入操作执行完毕才释放putLock。

    基于Rayland-C200的实现

    Rayland-C200和上述的稍有不同,Rayland-C200Rayland主板直接控制。走的是IIC

    IIC通信是同步半双工的。

    意味着我们程序里面收发不能同步执行,( 同时Rayland-C200没有针对指令的callback) 所以我们需要在Android实现收发的控制。

    MainActivity:

    
    private Runnable loop = new Runnable() {
    		public void run() {
    			while(runningLoop){
    				if(commands.isEmpty()){
    					idleLoop();
    				}else{
    					try {
    						current = commands.take();
    					} catch (InterruptedException e) {
    						if(!runningLoop) {
    							break ;
    						}
    					}
    					if(current!=null && runningLoop){
    						loop(current);
    					}
    				}
    			}
    		}
    	};
    
    

    LoopDeque:

    
    queue = new LoopQueue<SendCommand>(3) {
                @Override
                public void idleLoop() {
                    packet.read();
                   
                    try {
                        Thread.sleep(20);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
    
                @Override
                public void loop(final SendCommand command) {
                    SendPacket sendPacket = new SendPacket(command);
                    sendPacket.send();
                }
            };
            queue.startLoop();
    
    
  • 相关阅读:
    【JZOJ5603】【NOI2018模拟3.27】Xjz
    【JZOJ5605】【NOI2018模拟3.26】Arg
    【agc004e】Salvage Robots
    【agc004c】AND Grid
    【agc004d】Teleporter
    【agc002f】Leftmost Ball
    【agc002d】Stamp Rally
    【arc068F】Solitaire
    51nod 1172 Partial Sums V2
    快速数论变换NTT模板
  • 原文地址:https://www.cnblogs.com/chenjy1225/p/9662531.html
Copyright © 2011-2022 走看看