Donkey Car 센서를 통한 Hybrid 실행

18706 단어 donkeycar
개시하다
해외에서는 사람 조작과 AI 추론으로 주행 시간이 짧아지고 RC차의 하드웨어 성능에 의존하는 곳이 높아지면서 타이머 레이스가 거의 끝나지 않았다고 생각한다.최근 트랙에서 티스카를 주행하며 그 차를 피하면서 주행하는 등 천천히 내년부터 AI 추론만 하는 주행부터 센서를 보조적으로 사용한 하이브리드 방식의 주행 유행이라는 생각으로 논의를 시작한 내용이다.
현행 돈키카(3.1.1.1)에서 주행 추론에 따라 앞바퀴의 각도와 뒷바퀴를 제어하는 밸브는 각종 센서로부터의 정보를 바탕으로 주행 정밀도를 높이기 위해 다음과 같이 논의했다.
  • Raspberry Pi의 GPIO에 센서를 설치하는 방법
    imu.py(MPU6050)와 같은 방법이지만 센서가 많아지고 센서 제거 시간이 길어지면 전체 주기(DRIVE LOOP HZ=20)에 영향을 미치므로 향후 추론 모델의 복잡화 시간을 위해 주기는 유지하는 것이 좋다고 생각한다.
  • Arduino를 통한 센서 제어
    우리는 아두노를 전체 센서를 제어하는 협동 프로세서로 사용하는 것을 연구했다.센서 연결 사례도 많아 아날로그와 디지털 센서도 쉽게 연결된다.Raspberry Pi와의 연결은 I2C를 센서의 주 제어로 USB 직렬 통신을 통해 연결하는 것이다.
  • 구성도
    ·I2C나 SPI를 통해 아두노를 센서에 연결해 상태를 1바이트로 변환해 설정합니다.Write를 통해 USB를 통해 Raspberry Pi로 정기적으로 전송됩니다.
    Raspberry Pi의 SerialArduino.py는 Thread로 시작하여 항상 USB 직렬에서 최신 상태를 읽고 유지합니다 (self.status).
    ·Donkey의 주 순환에서 추론한 후 최신 상태를 사용하여 새로운 밸브 값을 구한다.

    사전 준비
    pip install pyserial
    
    참고 프로그램
    Arduino(Donkey_Sensor.ino)
    이 시료는 VL53L1X를 하나의 I2C에 연결해 측정된 최대 거리를 짧게(1.3m 정도)하고, 거리에 따라 속도 카테고리를 1바이트 문자로 설정해 랩베리 피 측으로 전송했다.디버깅을 위해 비교적 짧은 거리를 설정했다.
    /*
     *   Sensor controller for Donkey car
     *                            2019/12/02
     *   Ver. 0.1  single VL53L1
     *   
     *   command: 'F': Full throttle
     *            'M': Medium
     *            'S': Slow
     *            'E': Emergency Stop
     */
    #include <Wire.h>
    #include <VL53L1X.h>
    #define Threshold_M  450  // mm
    #define Threshold_S  250  // mm
    #define Threshold_E   50  // mm
    
    VL53L1X sensor;
    
    void setup()
    {
      Serial.begin(115200);
      Wire.begin();
      Wire.setClock(400000); // use 400 kHz I2C
    
      sensor.setTimeout(500);
      if (!sensor.init())
      {
        Serial.println("Failed to detect and initialize sensor!");
        while (1);
      }
      // long ... 50ms, medium ... 33ms, short ... 20ms
      sensor.setDistanceMode(VL53L1X::Short);
      sensor.setMeasurementTimingBudget(20000);
      // Start continuous readings at a rate of one measurement every 50 ms (the
      // inter-measurement period). This period should be at least as long as the
      // timing budget.
      sensor.startContinuous(50);
    }
    
    void loop()
    {
      int range;
      sensor.read();
    
      if(sensor.ranging_data.range_status == 0) {
        range = sensor.ranging_data.range_mm;
    
        if(range < Threshold_E) {
          Serial.write("E");
        } else {
          if(range < Threshold_S) {
            Serial.write("S");
          } else {
            if(range < Threshold_M) {
              Serial.write("M");
            } else {
              Serial.write("F");
            }
          }
        }      
      } else {
        Serial.write("F");  // out of range
      }
      delay(50);
    }
    
    Raspberry Pi(myconfig.py)
    다음 플래그를 추가합니다.
    # Sensor from Arduino
    SERIAL_ARDUINO = True
    
    Raspberry Pi(parts/serial_arduino.py)
    dev는/dev/ttyACM0 또는/dev/ttyUSB0일 수 있으므로 USB를 찔렀을 때 추가된 장치를 확인하는 것이 좋다.baudate는 Arduino의 Serial입니다.비긴과 같은 값을 미리 설정합니다.
    import serial
    import time
    
    class Serial_sense():
        '''
        get sensor information from Arduino via serial USB interface
        '''
    
        def __init__(self, dev='/dev/ttyUSB0', baudrate=115200, poll_delay=0.03):
            self.status = b'F'
            self.dev = dev
            self.baudrate = baudrate
            self.serial_port = serial.Serial(self.dev, self.baudrate)
            time.sleep(1)
            self.poll_delay = poll_delay
            self.on = True
    
        def update(self):
            while self.on:
                self.poll()
                time.sleep(self.poll_delay)
    
        def poll(self):
            try:
                self.status = self.serial_port.read()
            except:
                print('failed to read serial USB interface!!')
    
        def run_threaded(self):
            return self.status
    
        def run(self):
            self.poll()
            return self.status
    
        def shutdown(self):
            self.serial_port.close()
            self.on = False
    
    
    Raspberry Pi(parts/sensor_controller.py)
    샘플의 인코딩은 밸브의 출력을 각각 30%씩 낮추는 것이지만 이 부분은 실제 운행에 따라 수치를 결정하는 것이 좋다.
    최소 토크보다 작으면 멈추기 때문에 개체와 함께 최소 토크로 돌아가는 것이 좋다.
    class SensorController():
        '''
        This part is to control throttle from ToF sensor on Arduino.
        command: 'F': Full throttle   100%
                 'M': Medium           70%
                 'S': Slow             40%
                 'E': Emergency Stop    0%
        '''
        def __init__(self):
            self.power_dict = {b'\x00':0.0, b'F':1.0, b'M':0.7, b'S':0.4, b'E':0.0}
    
        def run(self, mode, ai_throttle, status):
            new_throttle = ai_throttle
            # temporary changing for debugging
            if mode == "local":
                power_rate = self.power_dict[status]
                new_throttle = new_throttle * power_rate
    
            return new_throttle
    
    Raspberry Pi(manage.py)
    IMU의 Thread를 추가하면 다섯 줄이 추가됩니다.
        #IMU
        if cfg.HAVE_IMU:
            from donkeycar.parts.imu import Mpu6050
            imu = Mpu6050()
            V.add(imu, outputs=['imu/acl_x', 'imu/acl_y', 'imu/acl_z',
                'imu/gyr_x', 'imu/gyr_y', 'imu/gyr_z'], threaded=True)
    
        #Serial USB interface
        if cfg.SERIAL_ARDUINO:
            from donkeycar.parts.serial_arduino import Serial_sense
            serial_sensor = Serial_sense(dev='/dev/ttyUSB0', baudrate=115200)       
            V.add(serial_sensor, outputs=['serial_sensor/status'], threaded=True)
    
    
    드라이브 트레인 setup 전에 7행을 추가합니다.
        #Throttle controller from sensors on Arduino   
        if cfg.SERIAL_ARDUINO:
            from donkeycar.parts.sensor_controller import SensorController
            sensor_controller = SensorController()       
            V.add(sensor_controller, 
                inputs=['user/mode', 'throttle', 'serial_sensor/status'],
                outputs=['throttle'])       
    
        #Drive train setup
        if cfg.DONKEY_GYM:
            pass
    
    최후
    이렇게 되면 센서에서 얻은 정보를 가공해 랩버리피로 이전의 기본적인 일련의 프로세스를 제어하면 이동한다.나는 모두가 각양각색의 지혜를 생각해 내어 재미있는 통제를 할 수 있기를 바란다.

    좋은 웹페이지 즐겨찾기