Шторы (arduino + mySensor)

Подключение исполнительных устройств, датчиков, контроллеров.

Модератор: immortal

Ответить
Аватара пользователя
Amarok
Сообщения: 1427
Зарегистрирован: Пт дек 14, 2012 12:24 pm
Откуда: Россия, Нижняя Тура
Благодарил (а): 460 раз
Поблагодарили: 126 раз
Контактная информация:

Шторы (arduino + mySensor)

Сообщение Amarok » Пт сен 04, 2015 10:15 am

Планирую собирать управляемые при помощи arduino и библиотеки mySensors шторы. Имеются в наличии:
Arduino UNO
Серво привод непрерывного вращения
111111111111111111111111111111111111.jpg
111111111111111111111111111111111111.jpg (19.84 КБ) 6429 просмотров
Скетч управления серой такой:
ServoActuator by MySensorsПоказать

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

/**
 * The MySensors Arduino library handles the wireless radio link and protocol
 * between your home built sensors/actuators and HA controller of choice.
 * The sensors forms a self healing radio network with optional repeaters. Each
 * repeater and gateway builds a routing tables in EEPROM which keeps track of the
 * network topology allowing messages to be routed to nodes.
 *
 * Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
 * Copyright (C) 2013-2015 Sensnology AB
 * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
 *
 * Documentation: http://www.mysensors.org
 * Support Forum: http://forum.mysensors.org
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * version 2 as published by the Free Software Foundation.
 *
 *******************************
 *
 * REVISION HISTORY
 * Version 1.0 - Henrik Ekblad
 * Contribution by: Derek Macias
 * 
 * DESCRIPTION
 * Example showing how to create an atuator for a servo.
 * Connect red to +5V, Black or brown to GND and the last cable to Digital pin 3.
 * The servo consumes much power and should probably have its own powersource.'
 * The arduino might spontanally restart if too much power is used (happend
 * to me when servo tried to pass the extreme positions = full load).
 * http://www.mysensors.org/build/servo
 */


#include <MySensor.h>
#include <SPI.h>
#include <Servo.h> 

#define SERVO_DIGITAL_OUT_PIN 3
#define SERVO_MIN 0 // Fine tune your servos min. 0-180
#define SERVO_MAX 180  // Fine tune your servos max. 0-180
#define DETACH_DELAY 900 // Tune this to let your movement finish before detaching the servo
#define CHILD_ID 10   // Id of the sensor child

MySensor gw;
MyMessage msg(CHILD_ID, V_DIMMER);
Servo myservo;  // create servo object to control a servo 
                // a maximum of eight servo objects can be created Sensor gw(9,10);
unsigned long timeOfLastChange = 0;
bool attachedServo = false;
            
void setup() 
{ 
  // Attach method for incoming messages
  gw.begin(incomingMessage);

  // Send the sketch version information to the gateway and Controller
  gw.sendSketchInfo("Servo", "1.0");

  // Register all sensors to gw (they will be created as child devices)
  gw.present(CHILD_ID, S_COVER);

  // Request last servo state at startup
  gw.request(CHILD_ID, V_DIMMER);
} 

void loop() 
{ 
  gw.process();
  if (attachedServo && millis() - timeOfLastChange > DETACH_DELAY) {
     myservo.detach();
     attachedServo = false;
  }
} 

void incomingMessage(const MyMessage &message) {
  myservo.attach(SERVO_DIGITAL_OUT_PIN);   
  attachedServo = true;
  if (message.type==V_DIMMER) { // This could be M_ACK_VARIABLE or M_SET_VARIABLE
     int val = message.getInt();
     myservo.write(SERVO_MAX + (SERVO_MIN-SERVO_MAX)/100 * val); // sets the servo position 0-180
     // Write some debug info
     Serial.print("Servo changed. new state: ");
     Serial.println(val);
   } else if (message.type==V_UP) {
     Serial.println("Servo UP command");
     myservo.write(SERVO_MIN);
     gw.send(msg.set(100));
   } else if (message.type==V_DOWN) {
     Serial.println("Servo DOWN command");
     myservo.write(SERVO_MAX); 
     gw.send(msg.set(0));
   } else if (message.type==V_STOP) {
     Serial.println("Servo STOP command");
     myservo.detach();
     attachedServo = false;

   }
   timeOfLastChange = millis();
}

Как поправить скетч так, чтобы вращение останавливалось при замыкании одного из герконов? Ну и чтобы ардуинка не расслаблялась, планирую добавить датчики температуры и движения.
Моя Алиска живёт на Proxmox в Debian 12
Anton_kulibin
Сообщения: 354
Зарегистрирован: Вт окт 09, 2012 8:05 am
Откуда: Луза Кировская обл. Россия
Благодарил (а): 20 раз
Поблагодарили: 35 раз

Re: Шторы (arduino + mySensor)

Сообщение Anton_kulibin » Пт сен 04, 2015 1:20 pm

Я уже год планирую). Гардина есть, мотор(не серва) есть,осталось только скетч собрать. У меня план такой:
Отправлять на сервер значение открыто/закрыто. И отправлять на датчик либо открыть либо закрыть.
Также надо определиться будут ли закрываться (диммированием), т.е. держишь закрываются/открываются пока не отпустишь (как бы на полное закрывание/открывание) или нажал начали закрываться снова нажал остановились, нажал стали открываться.
Логика как у секционных ворот))
Linux версия. Ubuntu Server 16.04+2xArduinoMega+Eth_GW_Mysensors_10node+WeatherStation+Xiaomi
CONNECT
Аватара пользователя
sergejey
Site Admin
Сообщения: 4286
Зарегистрирован: Пн сен 05, 2011 6:48 pm
Откуда: Минск, Беларусь
Благодарил (а): 76 раз
Поблагодарили: 1559 раз
Контактная информация:

Re: Шторы (arduino + mySensor)

Сообщение sergejey » Пт сен 04, 2015 1:31 pm

Ниже мой скетч, может пригодится для переделки в то, что нужно.

У меня сделано на приёмнике 433Mhz, он получает сигнал на закрытие либо открытие. Назад на сервер ничего не посылается. Так же есть кнопка, чтобы вручную начать процесс. По нажатию либо открывается либо закрывается либо останавливается, после остановки следующее нажатие меняет направление.

По железу практически так же как на схеме, только не на герконах, а на "микриках", но суть та же -- при замыкании движение останавливается и возможно только в обратную сторону. Дополнительно стоит защита по таймеру, чтобы двигатель не вращался более указанного времени не смотря ни на что. В будущем думал заменить концевики на датчик тока, чтобы двигатель отключался при привышении усилия, но руки так и не дошли.
СпойлерПоказать

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

#include <VirtualWire.h>
#include <EasyTransferVirtualWire.h>
#include <EEPROM.h> //Needed to access the eeprom read write functions

#define MAX_MOVING (15) // max seconds for motion
#define PIN_RELAY_1 (2) // RELAY 1
#define PIN_RELAY_2 (3) // RELAY 2
#define PIN_KEY_TOP (4)  // TOP REACHED KEY SENSOR
#define PIN_KEY_BOTTOM (5) // BOTTOm REACHED KEY SENSOR
#define PIN_KEY_SWITCH (6) // SWITCH BUTTOM KEY SENSOR
#define PIN_RF (7) // SWITCH BUTTOM KEY SENSOR
#define PIN_LED (13) // INDICATOR

#define CLASS_UPDOWN (14) // control class command
#define COMMAND_UP (1) // up command code
#define COMMAND_DOWN (2) // down command code
#define COMMAND_STOP (3) // stop command code
#define COMMAND_INVERT (4) // switch command code

unsigned int unique_device_id = 0;
unsigned int packet_received_id = 0;
int oldKeyTop=0;
int oldKeyBottom=0;
int oldKeySwitch=0;
int currentState=0; //0 = unknown, 1 = open, 2 = closed
int isMoving=0; // 0 = No, 1 = Yes
int canGoUp=0; // 0 = No, 1 = Yes
int canGoDown=0; // 0 = No, 1 = Yes
int oldDirection=2; // 0 = was moving to open, 1 = was moving to close, 2 = unknown
long int movingstarted=0; // time move started
long int keyPressed=0; // time keyPressed
//int delayHalpUp=2000;


EasyTransferVirtualWire ET; 

struct SEND_DATA_STRUCTURE {
  //put your variable definitions here for the data you want to send
  //THIS MUST BE EXACTLY THE SAME ON THE OTHER ARDUINO
  //Struct can'e be bigger then 26 bytes for VirtualWire version
  unsigned int device_id;
  unsigned int destination_id;  
  unsigned int packet_id;
  byte command;
  int data;
};

//give a name to the group of data
SEND_DATA_STRUCTURE mydata;

//This function will write a 2 byte integer to the eeprom at the specified address and address + 1
void EEPROMWriteInt(int p_address, unsigned int p_value)
      {
      byte lowByte = ((p_value >> 0) & 0xFF);
      byte highByte = ((p_value >> 8) & 0xFF);

      EEPROM.write(p_address, lowByte);
      EEPROM.write(p_address + 1, highByte);
      }

//This function will read a 2 byte integer from the eeprom at the specified address and address + 1
unsigned int EEPROMReadInt(int p_address)
      {
      byte lowByte = EEPROM.read(p_address);
      byte highByte = EEPROM.read(p_address + 1);

      return ((lowByte << 0) & 0xFF) + ((highByte << 8) & 0xFF00);
      }

void setup()
{
  digitalWrite(PIN_RELAY_1,HIGH);
  digitalWrite(PIN_RELAY_2,HIGH);
 
  pinMode(PIN_LED,OUTPUT);  
  pinMode(PIN_RELAY_1,OUTPUT);
  pinMode(PIN_RELAY_2,OUTPUT);  
  pinMode(PIN_KEY_TOP,INPUT);    
  pinMode(PIN_KEY_BOTTOM,INPUT);      
  pinMode(PIN_KEY_SWITCH,INPUT);        
 
  Serial.begin(9600);

  oldKeyTop=digitalRead(PIN_KEY_TOP);
  oldKeyBottom=digitalRead(PIN_KEY_BOTTOM);  
  oldKeySwitch=digitalRead(PIN_KEY_SWITCH);    
  
    ET.begin(details(mydata));
    // Initialise the IO and ISR
    vw_set_rx_pin(PIN_RF);
    vw_set_tx_pin(A1);
    vw_set_ptt_pin(A2);         
    vw_setup(2000);      // Bits per sec
    vw_rx_start();       // Start the receiver PLL running  
    
  // Device ID
  Serial.print("Getting Device ID... "); 
  unique_device_id=EEPROMReadInt(0);
  if (unique_device_id<10000 || unique_device_id>60000) {
   Serial.print("N/A, updating... "); 
   unique_device_id=random(10000, 60000);
   EEPROMWriteInt(0, unique_device_id);
  }
  Serial.println(unique_device_id);    

  canGoUp=1;
  canGoDown=1;
  
  if (oldKeyTop==HIGH) {
   currentState=1; // is open
   canGoUp=0;
   canGoDown=1;
  }
  if (oldKeyBottom==HIGH) {
   currentState=2; // is closed
   canGoUp=1;
   canGoDown=0;   
  }  
  oldDirection=2;
}

void blinking(int count) {
 for(int i=0;i<count;i++) {
  digitalWrite(PIN_LED, HIGH); 
  delay(200);
  digitalWrite(PIN_LED, LOW);
  delay(200);
 }
}

void openUp() {
 oldDirection=0;
 if (canGoUp!=1) {  
  Serial.println("ERROR: Cannot go UP!");     
  blinking(10);
 } else {
  Serial.println("Opening...");    
  digitalWrite(PIN_LED,LOW);
  isMoving=1;
  currentState=0;
  movingstarted=millis(); 
  digitalWrite(PIN_RELAY_1,HIGH);  
  digitalWrite(PIN_RELAY_2,LOW);    
 }
}

void closeDown() {
 oldDirection=1;  
 if (canGoDown!=1) {
  Serial.println("ERROR: Cannot go DOWN!");  
  blinking(10);  
 } else {
  Serial.println("Closing...");  
  digitalWrite(PIN_LED,LOW);
  isMoving=1;
  currentState=0; 
  movingstarted=millis();
  digitalWrite(PIN_RELAY_1,LOW);  
  digitalWrite(PIN_RELAY_2,HIGH);
 }
}

void stopMotion() {
 digitalWrite(PIN_RELAY_1,HIGH);  
 digitalWrite(PIN_RELAY_2,HIGH);   
 Serial.println("Stop!");    
 isMoving=0;
 digitalWrite(PIN_LED,HIGH);
}

void loop() {

  if (isMoving==1) {
   long int movingtime=millis()-movingstarted;
   if (movingtime>MAX_MOVING*1000) {
    Serial.println("Moving too long. Something wrong!");         
    stopMotion();
    currentState=0; 
   }
    //Serial.println("moving...");
  } else {
    //Serial.println("idle...");
  }
  
  int currentKeyTop=digitalRead(PIN_KEY_TOP);
  if (currentKeyTop==HIGH) {
    currentState=1; // is closed    
    canGoDown=0;
    canGoUp=1;
  } else {
    canGoDown=1;    
  }
  if (currentKeyTop!=(int)oldKeyTop) {
    oldKeyTop=(int)currentKeyTop;
    if (currentKeyTop==HIGH) {
      //top reached. stop.
      Serial.println("Is closed!");            
      stopMotion();
    }
  }
  
  int currentKeyBottom=digitalRead(PIN_KEY_BOTTOM);   
  if (currentKeyBottom==HIGH) {
    currentState=2; // is open
    canGoDown=1;
    canGoUp=0;
  } else {
   canGoUp=1;        
  }
  if (currentKeyBottom!=(int)oldKeyBottom) {
    oldKeyBottom=(int)currentKeyBottom;
    if (currentKeyBottom==HIGH) {
      //bottom reached. stop.
      Serial.println("Is Open!");      
      stopMotion();      
    }
  } 
 
  //begin easy transfer
  if (ET.receiveData()) {
    Serial.print("Got packet for device ");
    Serial.print(mydata.destination_id);        
    Serial.print(" packet ");
    Serial.print(mydata.packet_id);
    Serial.print(" command ");    
    Serial.print(mydata.command);    
    Serial.print(" data ");    
    Serial.println(mydata.data);
  
    if ((mydata.destination_id==unique_device_id) && (mydata.packet_id!=packet_received_id)) {
      
      Serial.print("Got RF command: ");
      Serial.print(mydata.command);
      Serial.print(" data: ");
      Serial.println(mydata.data);
      packet_received_id=(int)mydata.packet_id;
      blinking(5);
    
      char c='?';
    
      if (mydata.command==CLASS_UPDOWN) {
        if (mydata.data==COMMAND_UP) {
          c='u';
        }
        if (mydata.data==COMMAND_DOWN) {
          c='d';
        }
        if (mydata.data==COMMAND_STOP) {
          c='s';
        }      
        if (mydata.data==COMMAND_INVERT) {
          c='i';
        }      
      }
      if (c=='u') {
       Serial.println("UP command received");     
       openUp();
      } else if (c=='d') {
       closeDown();
      } else if (c=='s') {
       Serial.println("STOP command received");
       stopMotion();            
      } else if ((c=='i') && (isMoving==1)) {
       Serial.println("INVERT command received. Stop.");
       stopMotion();            
      } else if ((c=='i') && (isMoving==0)) {
       Serial.println("INVERT command received. Change direction.");
       if (oldDirection==0) {
         closeDown();
       } else if (oldDirection==1) {
         openUp();
       } else if (canGoUp==1) {
         Serial.println("Error. Unknown last direction. Opening UP.");
         openUp();
       } else if (canGoDown==1) {
         Serial.println("Error. Unknown last direction. Closing.");          
         closeDown();
       }
      }
      
   } else {
     Serial.println("Ignoring packet.");
   }
  } 
  // end easytransfer  
  
  if (Serial.available()) {
    char c=Serial.read();
    Serial.println(c);
    if (c=='u') {
     Serial.println("UP command received");     
     openUp();
    } else if (c=='d') {
     Serial.println("DOWN command received");           
     closeDown();
    } else if (c=='s') {
     Serial.println("STOP command received");
     stopMotion();            
    } else if ((c=='i') && (isMoving==1)) {
     Serial.println("INVERT command received. Stop.");
     stopMotion();            
    } else if ((c=='i') && (isMoving==0)) {
     Serial.println("INVERT command received. Change direction.");
     if (oldDirection==0) {
       closeDown();
     } else if (oldDirection==1) {
       openUp();
     } else if (canGoUp==1) {
       Serial.println("Error. Unknown last direction. Opening UP.");
       openUp();
     } else if (canGoDown==1) {
       Serial.println("Error. Unknown last direction. Closing.");          
       closeDown();
     }
    }
  }
  

 
  int currentKeySwitch=digitalRead(PIN_KEY_SWITCH);
  if ((currentKeySwitch!=(int)oldKeySwitch) && (millis()-keyPressed>100)) {
    keyPressed=millis();
    oldKeySwitch=(int)currentKeySwitch;
    if (currentKeySwitch==HIGH) {
      Serial.println("KeySwitch pressed.");      
      // key pressed
      if (isMoving==1) {
       Serial.println("Stop (manual).");         
       stopMotion();
       currentState=0;        
      } else if (isMoving==0) {
        Serial.println("Change direction (manual)...");                                   
        if (oldDirection==0) {
          closeDown();
        } else if (oldDirection==1) {
          openUp();
        } else if (canGoUp==1) {
          Serial.println("Error. Unknown last direction. Opening UP.");
          openUp();
        } else if (canGoDown==1) {
          Serial.println("Error. Unknown last direction. Closing.");          
          closeDown();
        }
      }
    }
  }    

 
  //delay(100);
}
 

Сергей Джейгало, разработчик MajorDoMo
Идеи, ошибки -- за предложениями по исправлению и развитию слежу только здесь!
Профиль Connect -- информация, сотрудничество, услуги
Аватара пользователя
shemnik69
Сообщения: 590
Зарегистрирован: Пн дек 24, 2012 3:01 pm
Откуда: Саратов Saratov
Благодарил (а): 67 раз
Поблагодарили: 63 раза

Re: Шторы (arduino + mySensor)

Сообщение shemnik69 » Пт сен 04, 2015 1:47 pm

У меня похожая логика, но вот в качестве канала обмена использовал ModBus! (хороший урок для этого вот: http://www.cyber-place.ru/showthread.ph ... d45d&t=623) есть и примеры и хорошо расписано. На мой не искушенный взгляд именно ModBus для таких простых задач идеален. К контроллеру ведет UTP где 1 пара это RS485 остальные это питание 12 в. (6 жил) по току легко пропустит до 2 А (т.е мощность около 24 Вт!!!) любой привод провернет, и сам провод достаточно удобен. И самое то главное что библиотека и управляющий код свободно живет в 8 атмеге! По поводу датчиков температуры. Тот же ModBus идеален для таких датчиков нужно всего две библиотеки и получаем данные как контактных датчиков так температурных. Пожалуй недостаток что Модбус не реализует "многомастерный" режим.
Сейчас "перепрошил" все Атмеги в контроллерах под ModBus (RS485) самое главное что решилась основная проблема это искажение данных при обмене а поскольку в протоколе Modbus это решено то канал стал по сути "идеален". да еще один момент.. "мучал" меня роутер МР3020 с передачей данных.
Решилось так: ставим на него Ser2Net настраиваем ser/// на USB (обязательно USB-2 HAB) и на порт 502 и все, получаем Modbus TCP. работает на ура!!!! те. можно предавать данные на Ардуино подобные контроллеры либо пром контроллеры (например OVen) через сеть.
Ответить