[Железо] Самодельный робот в среде умного дома WPF, Arduino и Major

Работа с конкретным оборудованием

Модераторы: immortal, newz20

Ответить
Ashton
Сообщения: 1
Зарегистрирован: Чт июл 11, 2013 11:35 am
Благодарил (а): 0
Поблагодарили: 0

[Железо] Самодельный робот в среде умного дома WPF, Arduino и Major

Сообщение Ashton » Чт июл 11, 2013 5:28 pm

Народ, всем привет! Сегодня я вам расскажу про свой проект. Создан он на мат.плате. MicroITX (Windows 7), через USB по COM-порту Arduino(отсылает данные в приложение), WPF приложением
(управляет Arduino и передает данные на сервер умного дома).

Отступление
Все началось 2 года, когда я подумывал сделать умный пылесос, долго проектировал, написал пару алгоритмов, чтобы
избежать столкновений, но все это мне показалось наивным, (ведь это уже кто-то сделал), чтобы, действительно, правильно убирать, он должен думать хотя бы немного как человек(он должен знать, что пол - это пол и т.д.). Работа продвигалась и я начал понимать, что робота этого можно использовать не только как "уборщика", но и создать нечто вроде "умного" дома.

Как это все работает
Чтобы робот знал, что пол - это пол, а так же мог определять некоторые вещи, я купил Kinect. Начал писать WPF приложение (так как под WPF куча примеров и информации про Kinect). Недолго думая я наладил общение Arduino и своего WPF приложения:
Так как Arduino будет постоянно находиться в роботе, разумно подключить его через USB и общаться с ним через COM-порт.
Логика общения довольна проста: из программы будем писать "фразы" в сериал монитор, а в ардуино на определенную "фразу" действие.
Сразу покажу код, чтобы не томить:

Код: Выделить всё

char inData[20]; // кол-во считываемых символов c Serial Monitorа
char inChar=-1; // записываем прочтенный символ
byte index = 0; // куда пишем

void setup() {
    pinMode(13, OUTPUT);
    Serial.begin(9600);
}

char key(char* This) {
    while (Serial.available() > 0) // не считывать до тех пор, пока данные не придут
    {
        if(index < 19)
        {
            inChar = Serial.read(); // чтение символа
            inData[index] = inChar; // запись символа
            index++; // место для следующего символа
            inData[index] = '\0';
        }
    }

    if (strcmp(inData,This)  == 0) {
        for (int i=0;i<19;i++) {
            inData[i]=0;
        }
        index=0;
        return(0);
    }
    else {
        return(1);
    }
}

void loop()
{
    if (key("led on")==0) {
       digitalWrite(13,HIGH);
    }
    if (key("led off")==0) {
       digitalWrite(13,LOW);
    }   
}
Теперь, если из WPF приложения послать в сериал монитор команду "led on", то загорится LED на 13 пине.
Ниже немного кода приложения для понимания:

Код: Выделить всё

 
using System.IO;    // подключаем библиотеку для работы c COM портом

private static readonly SerialPort SerialPort1 = new SerialPort();
SerialPort1.BaudRate = 9600;
SerialPort1.Open();

       public static void LEDoN()
        {
            SerialPort1.Write("led on"); //пишем в сериал монитор
        }
Так происходит общение с Arduino.

Итак, с первой проблемой общения мы разобрались. Разберемся с сервером:
Покажу на примере "выключателя" MajorDoMo. Допустим, нам нужно выключателем переключать чекбокс в WPF, и обратно (чекбоксом выключатель).
Логика общения заключается в следующем: WPF приложение посылает get/post запросы на сервер, один из запросов показывает текущее состояние выключателя, другой переключает выключатель, если значение изменилось, т.е. мы одним действием убиваем двух зайцев (не нужно посылать запросы с сервера).
Прежде чем переходить к WPF, сначала подготовим сервер.
Создаем выключатель и подключаем к нему объект.свойство (при изменении значения выключателя его значение будет записываться в свойство данного объекта, которое уже легко можно мониторить запросом). Все, сервер готов, переходим к WPF:
Создадим форму, на нее бросим 2 кнопки и 2 текстбокса, а также чекбокс.
Так же объявим глобальную переменную int status (можно сделать без глобальной переменной, я пишу лишь для примера)
POST запрос: POST("http://адрес/" , "данные");

Код: Выделить всё

  
      public static string POST(string Url, string Data)
        {
            System.Net.WebRequest req = System.Net.WebRequest.Create(Url);
            req.Method = "POST";
            req.Timeout = 100000;
            req.ContentType = "application/x-www-form-urlencoded";
            byte[] sentData = Encoding.GetEncoding(1251).GetBytes(Data);
            req.ContentLength = sentData.Length;
            System.IO.Stream sendStream = req.GetRequestStream();
            sendStream.Write(sentData, 0, sentData.Length);
            sendStream.Close();
            System.Net.WebResponse res = req.GetResponse();
            System.IO.Stream ReceiveStream = res.GetResponseStream();
            System.IO.StreamReader sr = new System.IO.StreamReader(ReceiveStream, Encoding.UTF8);
            //Кодировка указывается в зависимости от кодировки ответа сервера
            Char[] read = new Char[256];
            int count = sr.Read(read, 0, 256);
            string Out = String.Empty;
            while (count > 0)
            {
                String str = new String(read, 0, count);
                Out += str;
                count = sr.Read(read, 0, 256);
            }
            return Out;
        }
GET запрос: вызывать GET("http://адрес/" , "данные");

Код: Выделить всё

          public static string GET(string Url, string Data)
        {
            System.Net.WebRequest req = System.Net.WebRequest.Create(Url + "?" + Data);
            System.Net.WebResponse resp = req.GetResponse();
            System.IO.Stream stream = resp.GetResponseStream();
            System.IO.StreamReader sr = new System.IO.StreamReader(stream);
            string Out = sr.ReadToEnd();
            sr.Close();
            return Out;
        }
Коды кнопок (событие "клик"):
1) кнопка включить:

Код: Выделить всё

    
string Request = POST("http://192.168.0.106/index.php", "pd=Y29tbWFuZHM6e3BhcmVudF9pdGVtPTk3fQ%3D%3Dpz_YXBwbGljYXRpb246e2FjdGlvbj1tZW51fQ%3D%3Dpz_&md=commands&inst=&ajax=1&op=value_changed&item_id=103&new_value=1"); // value 1 - включаем выключатель =)
            xcoord_Copy.Text = Request;
2) кнопка выключить:

Код: Выделить всё

string Request = POST("http://192.168.0.106/index.php", "pd=Y29tbWFuZHM6e3BhcmVudF9pdGVtPTk3fQ%3D%3Dpz_YXBwbGljYXRpb246e2FjdGlvbj1tZW51fQ%3D%3Dpz_&md=commands&inst=&ajax=1&op=value_changed&item_id=103&new_value=0"); // value 0 - выключаем выключатель =)
            xcoord_Copy.Text = Request;
Функция мониторинга значения (запихиваем ее в таймер, время обновления(interval) выбираете как вам нужно)

Код: Выделить всё

        private void FollowStatus()
    {
       string Answer = GET("http://192.168.0.106/pChart/", "op=value&p=ThisComputer.FollowMode");
       xcoord_Copy1.Text = Answer;
       status = Convert.ToInt32(Answer);
            if (status == 1)
            {
                folowmod.IsChecked = true; // если галочка стоит на чекбоксе
            }

            if (status == 0)
            {
                folowmod.IsChecked = false; // если галочку сняли
            }
    }
Изменение состояния чекбокса:

Код: Выделить всё

        private void folowmod_Checked(object sender, RoutedEventArgs e)
        {

            if (folowmod.IsChecked == true)
            {
                string Request = POST("http://192.168.0.106/index.php", "pd=Y29tbWFuZHM6e3BhcmVudF9pdGVtPTk3fQ%3D%3Dpz_YXBwbGljYXRpb246e2FjdGlvbj1tZW51fQ%3D%3Dpz_&md=commands&inst=&ajax=1&op=value_changed&item_id=103&new_value=1");
                status = 1;
                xcoord_Copy.Text = Request;
            }

            if (folowmod.IsChecked == false)
            {
                string Request = POST("http://192.168.0.106/index.php", "pd=Y29tbWFuZHM6e3BhcmVudF9pdGVtPTk3fQ%3D%3Dpz_YXBwbGljYXRpb246e2FjdGlvbj1tZW51fQ%3D%3Dpz_&md=commands&inst=&ajax=1&op=value_changed&item_id=103&new_value=0");
                status = 0;
                xcoord_Copy.Text = Request;
            }
        }
Вот так достаточно просто происходит общение между Arduino, WPF приложением и MajorDoMo.

Питание
Arduino питается от двух 2400mAh аккумуляторов, Kinect = аккумулятор + стабилизатор, а для MicroITX (для моих требований) подойдет это

Сейчас
Мой робот способен распознавать голос, отвечать (независимо от сервера), распознавать людей и рисовать их "скелет", есть функция следования за человеком (ее можно активировать через MajorDoMo, т.е. с любого устройства), снимать видео, видеть в абсолютной темноте (можно использовать как прибор ночного виденья), делать фото, его легко подключить к любому телевизору (hdmi) и посмотреть любимый фильм, или послушать музыку. В дальнейшем я планирую докупить датчиков (газа, температуры и подобные) и наконец встроить в него пылесос)).
Так же можно настроить инфракрасные передатчики и управлять телевизором и кондиционером, но для каждого устройства придется предварительно посканировать коды(отследить сигнал определенной кнопки пульта управления, например, телевизором), пусть это займет много времени, но зато 1 раз посканировать и без проводов =)

Скрины
Изображение
Изображение

Помощь
Мне 18 лет и я недавно закончил школу, у меня неплохие знания, но мне нужна помощь в программировании, кому несложно пишите
skype: antoshka741
Аватара пользователя
sergejey
Site Admin
Сообщения: 4279
Зарегистрирован: Пн сен 05, 2011 6:48 pm
Откуда: Минск, Беларусь
Благодарил (а): 75 раз
Поблагодарили: 1533 раза
Контактная информация:

Re: Самодельный робот в среде умного дома WPF, Arduino и Maj

Сообщение sergejey » Пт июл 12, 2013 11:26 am

отличный проект! держи в курсе разработок :)

Сергей Джейгало, разработчик MajorDoMo
Идеи, ошибки -- за предложениями по исправлению и развитию слежу только здесь!
Профиль Connect -- информация, сотрудничество, услуги
Sayler
Сообщения: 54
Зарегистрирован: Пн ноя 28, 2016 9:15 pm
Благодарил (а): 21 раз
Поблагодарили: 2 раза

Re: Самодельный робот в среде умного дома WPF, Arduino и Major

Сообщение Sayler » Вс май 27, 2018 11:30 am

Интересно как проект продвинулся за это время. И кто нибудь подобным уже занимался?
Ответить