URM37 - побеждаем датчик.

Тема в разделе "Схемотехника, компоненты, модули", создана пользователем ИгорьК, 13 мар 2014.

  1. ИгорьК

    ИгорьК Гуру

    Да, он работает. Этот странный датчик, по цене пяти народных.
    Работает как-то так:


    Приобрел я его по случаю в количестве двух штук, когда делал самый первый проект на Ардуино. Мучился с ним безумно долго, как-то запустил... А второй оказался нерабочим. Или я его "убил" в процессе мучений. В общем, после осознания смерти, изучение интернета показало, что есть много других измерителей расстояний.
    Валялся бы одинокий URM себе еще, но работа над второй версией подсветки лестницы предъявила к ультрасонику повышенное требование - скорость. И я вспомнил, что 990 рублей, потраченные на этот датчик, хоть как-то должны вернуться - у датчика есть некоторые особенности (хотя не факт, что они стоят именно столько).
    Еще день мучений, и теперь я могу пошагово рассказать вам как включить автоматический режим работы этого датчика, когда он:
    - сам измеряет расстояние;
    - сам сравнивает с референсным;
    - сам дрыгает ножку, если расстояние меньше запланированного;
    - сам выдает PWM сигнал, который позволяет без напряга узнать расстояние.​
    Сначала скетч. А потом пояснения к нему, которых будет больше скетча.
    Код (C):
    // # Connection:
    // #      Pin 1 VCC (URM V3.2) -> VCC (Arduino)
    // #      Pin 2 GND (URM V3.2) -> GND (Arduino)
    // #      Pin 6 COMP/TRIG (URM V3.2) -> Pin 2 (Arduino)
    // #      Pin 4 PWM (URM V3.2) -> Pin 7 (Arduino)

    int cmmd1[]={
    0x44,0x00,0x05,0x49};//low byte stored in the sensor for the distance threshold.
    int cmmd2[]={
    0x44,0x01,0x00,0x45};//high byte, write 0x0010 into address 0x01 and 0x00,so the threshold is set to 16cm
    int cmmd3[]={
    0x44,0x02,0xaa,0xf0};// Autonomous mode. write 0xaa into address 0x02
    //int cmmd3[]={
    //  0x44,0x02,0xbb,0x01};  // PWM mode. write 0xbb into address 0x02
    int i;
    unsigned int pwmUrm;

    void setup(){
        Serial.begin(9600);                        // Sets the baud rate to 9600
        A_Mode_Setup();                            //PWM mode setup function
        pinMode(13, OUTPUT);
    }

    void loop()
    {
        pwmUrm = pulseIn(7, LOW);
        Serial.println(pwmUrm/50);       // Узнаем через порт расстояние;
        //delay(1000);
        byte s = digitalRead(2);
        Serial.println(s);               // Наблюдаем за срабатыванием на 5 см;
        digitalWrite(13,!s);
    }

    void A_Mode_Setup(){
        //write the data into the URM37 EEPROM
        for (i=0;i<4;i++)
        Serial.write(cmmd3[i]);
        delay(200);

        for (i=0;i<4;i++)
        Serial.write(cmmd1[i]);
        delay(200);

        for (i=0;i<4;i++)
        Serial.write(cmmd2[i]);
        delay(200);
    }
     
    Последнее редактирование: 18 мар 2014
  2. ИгорьК

    ИгорьК Гуру

    Итак, если вы соедините все как указано в скетче и запустите его - ничего полезного не случится. Хотя скетч абсолютно рабочий. В чем прикол? Прикол в том, что включать/выключать всю конструкцию надо по-особенному. Итак:
    1. присоединяем проводочки так, как указано в скетче, грузим его в Ардуино и не обращаем внимание на то, что ничего не получается. Главное - прошиться;
    2. все отключаем от электронов, то есть обесточиваем;
    3. находим еще два проводочка, и соединяем их так: 9 ножка URM - 0 ножка Ардуино, 8 ножка URM - 1 ножка Ардуино. Догадались? Да, это будет uart соединение;
    4. откладываем в сторонку кабель USB, находим 5вольт и запитываем Ардуинку именно таким образом - только внешним источником питания;
    5. чуть ждем когда оно замигает, заработает;
    6. находим кнопочку сброса на Ардуинке и нажимаем с любовью (это очень важно, иначе с URMом не справиться!);
    7. отпускаем кнопочку и еще немного ждем;
    8. отсоединяем Ардуино от питания;
    9. отсоединяем проводки от 0 и 1 входов Ардуинки;
    10. включаем питание вновь...
    И вот он, момент истины. Только если Вы любите и Ардуино, и датчик URM (в особенности), то при поднесении ладошки к нему на пять сантиметров загорится лампочка диода на 13 ножке.
    ... а почему именно на 5 см. и как это расстояние изменить, и как читается вообще расстояние - объясню завтра. Хотя из кода кое-что может быть понятно...
     
    Последнее редактирование: 31 мар 2014
    sys, kipill и acos нравится это.
  3. ИгорьК

    ИгорьК Гуру

    Теперь разберемся с тем, что же мы натворили.
    Но перед этим узнаем, что URM37 работает в трех режимах по выбору:
    1. по UART после получения запроса отвечает измеренным расстоянием;
    2. после пинка в ногу 6 отвечает о расстоянии PWM на 4 ноге ;
    3. сам измерят дистанцию раз в 25 мс., сам щелкает 6 ногой о том, ближе или дальше чем задумано, а на 4 ноге постоянно держит PWM сигнал для чтения дистанции.
    Вот этот, третий режим мы и прихватили сейчас. Как мы это сделали?
    Все переключения режимов и объяснения строптивому URM37 правил жизни осуществляются только по UART. Это необходимо запомнить. Причем режим 1 включен постоянно - ультрасоник всегда готов пообщаться по протоколу. Второй и третий режимы включаются путем подачи UART команд, сотстоящих из 4 байтов.
    Для включения третьего режима надо подать три команды. Первая и вторая (младший байт расстояния, старший байт расстояния) запоминает в памяти ультрасоника контролируемое расстояние, а третья, собственно, и включает режим.
    Рассмотрим первую команду - младший байт:
    { 0x44,0x00,0x05,0x54} 0x44 - запись во внутреннюю память, 0x00 - адрес памяти, 0х05 - наши 5 см, 0x54 - (обязательно!) сумма первых трех цифр. Считать ее очень просто. Находите на вашем компе стандартную программу Калькулятор, включаете Вид -> Программист... а дальше сами разберетесь.
    Теперь понятно, что команда {0x44,0x01,0x00,0x45} значит записать во внутреннюю память по адресу 0х01 число 0, а в сумме 0x44+0x01+0x00= 0x45.
    Третья команда тоже разъясняется. {0x44,0x02,0xaa,0xf0} Записать в ячейку 03 число 0хаа (что и значит войти в третий режим), а сумма этого действа - 0xf0.
    Ясно и то, для чего исполняются все манипуляции со включением-выключением. Поскольку UART задействуется для связи и с USB и с URM37, вместе они не работают. Значит всегда последовательность будет такой. Программируем Ардуино, отсоединяем от USB, но присоединяем к URM37, включаем, происходит запись по UART, после чего ультрасоник еще и требует перезагрузки - отключения и включения питания.
     
    Последнее редактирование: 31 мар 2014
    sys и kipill нравится это.
  4. ИгорьК

    ИгорьК Гуру

    Во втором и третьем режиме на 4 ноге ультрасоника по команде (2 режим) или постоянно (третий режим) присутствует PWM сигнал, который мы ловим командой pulseIn((номер присоединенной ноги Ардуино), LOW);. Его каждые 50 мкс соответствуют 1 см. значит поделив результат на 50 мы получаем расстояние в сантиметрах. Проще не куда! Вот и этот код:
    Код (Text):
    pwmUrm = pulseIn(7, LOW);
    Serial.println(pwmUrm/50);
    А код
    Код (Text):
    byte s = digitalRead(2);
    Serial.println(s);
    digitalWrite(13,!s);
    читает 6 ногу ультрасоника, печатает значение (0 или 1) в порт и зажигает лампочку, причем с инверсией. Ультрасоник держит на 6 ноге единицу, если расстояние больше указанного, и 0 - если меньше.
     
    sys и kipill нравится это.
  5. ИгорьК

    ИгорьК Гуру

    Наконец, пора записать другое расстояние в память. Давайте, предположим, 330 см. Алгоритм:
    1. открываем Калькулятор и записываем в него 330 в десятичном виде;
    2. переключаем в шестнадцатеричный и получаем 14А;
    3. врубаемся, что младший байт расстояния - 0х4а, а старший 0х01;
    4. составляем первую команду: 0x44,0x00,0x4а,0x8e. Понятно, что 0x8e = 0x44+0x00+0x4а? Кстати, калькулятор то не закрываем - это я на нем и посчитал.
    5. вторая команда: 0x44,0x01,0x00,0х45.
    6. третья: 0x44,0x02,0xaa,0xf0. Ее и считать не надо - просто копируем.
    Повторяем все описанные выше волшебные пассы, и наш умный URM размера 37 начинает контролировать дистанцию 330 см.
     
    Последнее редактирование: 14 мар 2014
    sys и kipill нравится это.
  6. ИгорьК

    ИгорьК Гуру

    А теперь превратим URM37 в обычный датчик. Для этого вместо трех команд запишем в память всего одну: {0x44,0x02,0xbb,0x01}; Разбирать ее нет смысла - проще записать. А для дотошных - запись в память по адресу 2 числа 0xbb. Сумма 0x44 + 0x02 + 0xbb равна 0х0101, но в команду подается младший байт, а именно - 0х01.
    Это, в целом, все. Добавлю, что пятой ногой ультрасоник может командовать сервой. Как это делается, желающие могут разобраться самостоятельно, уверен, предоставленной выше информации хватит для укрощения девайса.
    И напоследок две главные ссылки, где есть больше объяснений и материалов: раз и два.
     
    sys, atompost и kipill нравится это.
  7. ИгорьК

    ИгорьК Гуру

    Достал, улыбнулся... :D. Два года прошло.
    Стряхнул пыль.

    5553.jpg
    Загрузил скрипт:

    Код (Javascript):
    var cmd=[];
    var count = 0;
    var distance = 0;


    C3.set();   // light on
    SPI1.setup({sck:A5, miso:A6, mosi:A7, baud: 1000000});

    Serial6.setup(9600);
    Serial6.on('data', function (data) {
      // console.log(data.charCodeAt(0));
      cmd[count] =data.charCodeAt(0);
      count +=1;
      if (count === 4){
        // console.log(cmd);
        getDistanse(cmd);
        cmd = [];
        count = 0;
       }
    });

    var cmmd3=[0x44,0x02,0xaa,0xf0];// Autonomous mode
    var cmmd4=[0x44, 0x02, 0xbb, 0x01]; // passive PWM mode
    Serial6.write(cmmd4);

    var cmmd5=[0x11,0x00,0x00,0x11]; // temperature
    var cmmd6=[0x22,0x00,0x00,0x22]; // distance

    function getDistanse(rawdata) {
      if(rawdata[0] !== 255) {
        var newdistance = (rawdata[1]*255+rawdata[2]);
        if (newdistance !== distance) {
          console.log("Distance is "+ newdistance +" cm.");
          //printLCD("123");
          distance = newdistance;
        }
        return newdistance;
      }
      else{
        console.log("Error to get distance!");
        return rawdata[0];
      }
    }

    Serial6.write(cmmd6);
    setInterval(function(){
      Serial6.write(cmmd6);
    }, 1000);

    var g = require("ILI9341").connect(SPI1, B1, B0, C2, function() {
      g.setFontVector(45);
      g.setColor(0,0.5,1);
      var oldolddistance = 0;
      setInterval( function () {
        if (distance !== oldolddistance) {
          g.clear();
          var r = Math.random();
          var gr = Math.random();
          var b = Math.random();
     
          while ((r+gr+b) < 1) {
            r  = Math.random();
            gr = Math.random();
            b  = Math.random();
          }
          g.setColor(r,gr,b);
          g.drawString(distance + " cm.",45,150);
          oldolddistance = distance;
        }
      },2000 );
    });
     
    Последнее редактирование: 9 июн 2016
    sys нравится это.