Контролируем GoPro через WiFi с помощью Ардуино

В этом уроке мы покажем вам, как просто управлять GoPro Hero 4 и GoPro Hero Session 5 с помощью Wi-Fi и платы Arduino. В целом, эти рекомендации могут быть легко адаптированы для любого типа GoPro.

Это полезная штука, когда вы хотите создать собственный пользовательский контроллер для таких целей. Вместо того, чтобы взламывать существующие контроллеры, вы можете просто использовать Arduino для связи с GoPro напрямую, используя некоторые базовые сетевые команды. Вы не только можете контролировать функциональность GoPro, но также можете получать обновления о состоянии камеры. Это делает его универсальным решением для множества различных типов проектов, включая пользовательские роботы и беспилотные летательные аппараты.

Шаг 1. Комплектующие

Для этого проекта вам потребуется всего несколько вещей.

Для начала, очевидно, понадобится камера GoPro. Все инструкции должны работать для самой последней модели (GoPro Hero 6). Хотя, всё протестировано с GoPro Hero 4 и GoPro Hero Session 5. Модели Hero Session немного отличаются по контролю, чем другие модели, но планируем также их рассмотреть.

Также понадобится Arduino MKR1000 или Arduino MKR Zero. Здесь используется MKR1000. Можно работать с другим совместимым с Arduino беспроводным микроконтроллером с поддержкой Wi-Fi.

Вам также понадобится USB-кабель для Arduino, компьютер, на котором работает программное обеспечение Arduino IDE (которое, как я полагаю, у вас есть), и смартфон с установленным GoPro-приложением.

Если у вас нет опыта и вы раньше не использовали Arduino, настоятельно рекомендуем вам сначала посмотреть класс Arduino перед тем, как начать этот проект.

Шаг 2. Настройка Wi-Fi вашей камеры

Первое, что вам нужно сделать, это включить и настроить Wi-Fi-соединение вашей камеры. Не будем вдаваться в это слишком глубоко, потому что для этого уже есть много уроков и рекомендаций. На GoPro Hero 4 самый простой способ сделать это - подключить камеру к телефону, следуя указаниям в приложении.

После того, как телефон связан с камерой, откройте настройки камеры с помощью приложения и дайте Wi-Fi сети новое имя и пароль по вашему выбору.

На GoPro Hero 5 применяется тот же метод. Для начала подключите камеру к телефону, следуя инструкциям в приложении. Это автоматически настроит имя и пароль сети Wi-Fi.

Чтобы просмотреть имя сети Wi-Fi на вашей камере, перейдите к «Информация о камере» (англ. - Camera Info), которая находится в меню «Настройки подключения» (англ. - Connection Settings).

Шаг 3. Поиск MAC-адреса GoPro

После того как Wi-Fi включен, вам нужно выяснить, какой MAC-адрес вашей камеры. Этот адрес хорошо бы знать когда имеете дело с традиционной линейкой GoPro Hero. Однако, если вы используете GoPro Hero Session этот адрес является обязательным.

Чтобы получить его, сначала подключите свой компьютер к сети Wi-Fi вашей камеры, используя имя сети и пароль с предыдущего шага.

Как только вы войдете в сеть Wi-Fi вашей камеры, откройте любой старый веб-браузер на своем компьютере и перейдите по следующему URL-адресу:

http://10.5.5.9/gp/gpControl/info

Этот URL-адрес должен печатать строку информации в вашем веб-браузере, которая выглядит примерно так:

{"model_number"21,"model_name":"HERO5Session", "firmware_version":"HD5.03.02.51.00", "serial_number":"C3212365684485","board_type":"0x05", "ap_mac":"0641631510c4", "ap_ssid":"GP54688615", "ap_has_default_credentials":"0","capabilities":"16"}

Если это не так, убедитесь, что ваша камера включена и все еще подключена к Wi-Fi.

Нас интересует строка чисел, которая следует за «ap_mac:». Эта 12-значная строка цифр и является MAC-адресом. В данном случае это - 0641631510c4.

Как только вы определили адрес, разделите его на два символа и отформатируйте его следующим образом:

0x06, 0x41, 0x63, 0x15, 0x10, 0xC4

Шаг 4. Подключение Arduino к GoPro Hero

Для того, чтобы Arduino общался с камерой серии GoPro Hero, ее необходимо соединить с помощью PIN-кода. Чтобы получить pin, перейдите в меню телефона для соединения камеры с приложением. Это должно сгенерировать 4-значный PIN-код на всех камерах последующих моделей (у Hero 3 и ранее есть 6-значный PIN-код). Pin живет всего 3 минуты.

Вам нужно вручную вставить PIN два раза в код ниже в обоих местах, где:

//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//ENTER YOUR PIN HERE WHERE IT SAYS XXXX
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

После ввода pin-а у вас есть менее трех минут, чтобы загрузить его в Arduino и установить соединение с камерой.

Не забудьте ввести учетные данные Wi-Fi GoPro в этом месте:

//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//ENTER YOUR WIFI NAME AND PASSWORD HERE 
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

Во всех смыслах и целях, как только вы успешно загрузили код, ничего не появится. Тем не менее, если вы перейдете из меню настройки GoPro обратно к экрану видео, вы сможете теперь отправлять команды (которые мы рассмотрим ниже).

Если на следующих шагах вы не сможете отправить команды на камеру, вернитесь назад и повторите этот шаг. Код для связки GoPro с Arduino с использованием его PIN-кода:

#include <SPI.h>
#include <WiFi101.h>
#include <WiFiUdp.h>



int status = WL_IDLE_STATUS;

  //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  //ENTER YOUR WIFI NAME AND PASSWORD HERE
  //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 

char ssid[] = "XXXXXXXXXXXX"; //  your network SSID (name)
char pass[] = "XXXXXXXXXXXX";    // your network password (use for WPA, or use as key for WEP)

WiFiClient client;

const char* host = "10.5.5.9";
const int httpPort = 80;


void setup(){  

  //Initialize serial and wait for port to open:
  Serial.begin(115200);


  // check for the presence of the wifi module:
  if (WiFi.status() == WL_NO_SHIELD) {
     Serial.println("WiFi not present");
     // don't continue:
     while (true);
  }

  // attempt to connect to Wifi network:
  while ( status != WL_CONNECTED) {
    Serial.print("Attempting to connect to SSID: ");
    Serial.println(ssid);
    // Connect to WPA/WPA2 network. Change this line if using open or WEP network:
    status = WiFi.begin(ssid, pass);

    // wait 8 seconds for connection:
    delay(8000);
  }

  Serial.println("Connected to wifi");
  printWifiStatus();


  // START PIN
  StartPin();

  delay(10000);

  // FINISH PIN
  FinishPin();


}


void loop(){

  //Nothing to do here!
  delay(1000);

}


void StartPin(){
  Serial.print("connecting to ");
  Serial.println(host);

  if (!client.connect("10.5.5.9", httpPort)) {
    Serial.println("connection failed");
    return;
  }

  //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  //ENTER YOUR PIN HERE WHERE IT SAYS XXXX
  //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!  
  
  String StartUrl = "/gpPair?c=start&pin;=XXXX&mode;=0";
  Serial.print("Requesting URL: ");
  Serial.println(StartUrl);
  client.print(String("GET ") + StartUrl + " HTTP/1.1\r\n" +
  "Host: " + host + "\r\n" +
  "Connection: close\r\n\r\n");
  Serial.println("Started");
}



void FinishPin(){
  Serial.print("connecting to ");
  Serial.println(host);
  
  if (!client.connect("10.5.5.9", httpPort)) {
    Serial.println("connection failed");
    return;
  }

  //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  //ENTER YOUR PIN HERE WHERE IT SAYS XXXX
  //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  
  String StopUrl = "10.5.5.9/gpPair?c=finish&pin;=XXXX&mode;=0";
  Serial.print("Requesting URL: ");
  Serial.println(StopUrl);
  client.print(String("GET ") + StopUrl + " HTTP/1.1\r\n" +
  "Host: " + host + "\r\n" +
  "Connection: close\r\n\r\n");
  Serial.println("Finished");
}



void printWifiStatus() {
  // print the SSID of the network you're attached to:
  Serial.print("SSID: ");
  Serial.println(WiFi.SSID());

  // print your WiFi shield's IP address:
  IPAddress ip = WiFi.localIP();
  Serial.print("IP Address: ");
  Serial.println(ip);

  // print the received signal strength:
  long rssi = WiFi.RSSI();
  Serial.print("signal strength (RSSI):");
  Serial.print(rssi);
  Serial.println(" dBm");
}

Шаг 5. Подключение Arduino к GoPro Hero Session

GoPro Session не содержит ПИН-код. Однако у неё есть свои особенности, которые делают подключение к ней действительно раздражающим. Как вы могли заметить, как только вы закончите запись, или, если на то пошло, как только вы закончите делать что-либо с камерой, она выключится и перейдет в спящий режим.

Прежде чем вы сможете отправить GoPro Hero любую команду, вам нужно ее "разбудить". Самый простой способ сделать это - вручную нажать кнопку меню на задней панели камеры и отправить команды в течение нескольких секунд, в которых она "бодрствует". Однако это раздражает и не особенно практично.

Лучший способ разбудить GoPro - это использовать WOL-пакет или «волшебный пакет». Этот аббревиатура означает Wake-on-Lan и является протоколом для дистанционного пробуждения компьютера из спящего режима. Это требует отправки байтов с использованием протокола UDP от Arduino к GoPro, чтобы разбудить её. Это немного раздражает, потому что это другой протокол, чем тот, каким вы отправляете все остальные команды управления. Код также менее симпатичный, и с ним немного сложнее справиться, если вы новичок в программировании.

Тем не менее, когда он работает, он действительно работает как магия. Никогда не перестает удивлять, когда камера просыпается, отправив ей команду от Arduino.

Команда WOL (функция CameraInitiate() в коде) должна быть отправлена ​​перед большинством других команд и обычно должна сопровождаться задержкой в ​​1-2 секунды. По сути, вам нужно отправить её в любое время, когда вам может понадобиться разбудить камеру. И после того, как вы отправите команду, вам нужно сделать паузу на мгновение, чтобы камера действительно проснулась.

В приведенном ниже примере функция WOL вызывается в настройке, поэтому она будет только будить вашу камеру при первом запуске. Не забудьте ввести учетные данные Wi-Fi GoPro и MAC-адрес в код.

Сам код для GoPro Session:

#include <SPI.h>
#include <WiFi101.h>
#include <WiFiUdp.h>



int status = WL_IDLE_STATUS;

  //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  //ENTER YOUR WIFI NAME AND PASSWORD HERE
  //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 

char ssid[] = "XXXXXXXXXXXX"; //  your network SSID (name)
char pass[] = "XXXXXXXXXXXX";    // your network password (use for WPA, or use as key for WEP)

int localPort = 7;
byte broadCastIp[] = { 10,5,5,9 };

  //!!!!!!!!!!!!!!!!!!!!!!!!!!!
  //ENTER YOUR MAC ADDRESS HERE
  //!!!!!!!!!!!!!!!!!!!!!!!!!!! 

byte remote_MAC_ADD[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
int wolPort = 9;


WiFiUDP Udp;

WiFiClient client;

const char* host = "10.5.5.9";
const int httpPort = 80;


void setup(){  

  //Initialize serial and wait for port to open:
  Serial.begin(115200);

  // check for the presence of the wifi module:
  if (WiFi.status() == WL_NO_SHIELD) {
     Serial.println("WiFi not present");
     // don't continue:
     while (true);
  }

  // attempt to connect to Wifi network:
  while ( status != WL_CONNECTED) {
    Serial.print("Attempting to connect to SSID: ");
    Serial.println(ssid);
    // Connect to WPA/WPA2 network. Change this line if using open or WEP network:
     status = WiFi.begin(ssid, pass);

    // wait 8 seconds for connection:
    delay(8000);
  }

  Serial.println("Connected to wifi");
  printWifiStatus();

  delay(1000);

  // WAKE UP YOUR SLEEPY CAMERA!
  CameraInitiate(){

  // NOTE: If this does not seem to be working, 
  // turn your camera on and off and try again.

}


void loop(){

  //Nothing to do here!
  delay(1000);

}



// FUNCTION TO WAKE UP THE CAMERA

void CameraInitiate(){

  //Begin UDP communication
  Udp.begin(localPort);

  //Send the magic packet to wake up the GoPro out of sleep
  delay(2000);
  SendMagicPacket();
  delay(5000);  

  // Absolutely necessary to flush port of UDP junk for Wifi client communication
  Udp.flush();
  delay(1000);

  //Stop UDP communication
  Udp.stop();
  delay(1000);

}


// Function to create and send magic packet
// Taken and translated from here:
// https://www.logicaprogrammabile.it/wol-accendere-computer-arduino-wake-on-lan/

void SendMagicPacket(){

  //Create a 102 byte array
  byte magicPacket[102];

  // Variables for cycling through the array
  int Cycle = 0, CycleMacAdd = 0, IndexArray = 0;

  // This for loop cycles through the array
  for( Cycle = 0; Cycle < 6; Cycle++){

    // The first 6 bytes of the array are set to the value 0xFF
    magicPacket[IndexArray] = 0xFF;

    // Increment the array index
    IndexArray++;
  }

  // Now we cycle through the array to add the GoPro address
  for( Cycle = 0; Cycle < 16; Cycle++ ){
    //eseguo un Cycle per memorizzare i 6 byte del
    //mac address
    for( CycleMacAdd = 0; CycleMacAdd < 6; CycleMacAdd++){
      
      magicPacket[IndexArray] = remote_MAC_ADD[CycleMacAdd];
      
      // Increment the array index
      IndexArray++;
    }
  }

  //The magic packet is now broadcast to the GoPro IP address and port
  Udp.beginPacket(broadCastIp, wolPort);
  Udp.write(magicPacket, sizeof magicPacket);
  Udp.endPacket();

}


void printWifiStatus() {
  // print the SSID of the network you're attached to:
  Serial.print("SSID: ");
  Serial.println(WiFi.SSID());

  // print your WiFi shield's IP address:
  IPAddress ip = WiFi.localIP();
  Serial.print("IP Address: ");
  Serial.println(ip);

  // print the received signal strength:
  long rssi = WiFi.RSSI();
  Serial.print("signal strength (RSSI):");
  Serial.print(rssi);
  Serial.println(" dBm");
}

Шаг 6. Передача команд GoPro

В этом примере  отправляем команды для запуска и остановки видеозаписи.

Тем не менее, используя тот же метод, продемонстрированный здесь, вы можете отправлять команды практически для каждой функциональности в камере. Команды GoPro Hero 4, как представляется, являются стандартными для всех последующих моделей. Тем не менее, некоторые из последних камер имеют новые функции и специальные команды, которые стоит исследовать. Вы можете найти конкретные команды камеры на странице github API-интерфейса Unofficial GoPro WiFi, щелкнув ссылку для конкретной модели камеры.

Пример ниже включает запись в течение 5 секунд, прекращает запись, ждет еще 5 секунд и начинается снова. Если вы используете Hero Session, обязательно раскомментируйте строку кода, которая будит GoPro!

Еще раз, не забудьте ввести ваши учетные данные Wi-Fi GoPro и MAC-адрес!

Код для отправки команд «Старт и Стоп»:

#include <SPI.h>
#include <WiFi101.h>
#include <WiFiUdp.h>



int status = WL_IDLE_STATUS;

  //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  //ENTER YOUR WIFI NAME AND PASSWORD HERE
  //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 

char ssid[] = "XXXXXXXXXXXX"; //  your network SSID (name)
char pass[] = "XXXXXXXXXXXX";    // your network password (use for WPA, or use as key for WEP)

int localPort = 7;
byte broadCastIp[] = { 10,5,5,9 };

  //!!!!!!!!!!!!!!!!!!!!!!!!!!!
  //ENTER YOUR MAC ADDRESS HERE
  //!!!!!!!!!!!!!!!!!!!!!!!!!!! 

byte remote_MAC_ADD[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
int wolPort = 9;


WiFiUDP Udp;

WiFiClient client;

const char* host = "10.5.5.9";

const int httpPort = 80;


void setup(){  

  //Initialize serial and wait for port to open:
  Serial.begin(115200);


  // check for the presence of the wifi module:
  if (WiFi.status() == WL_NO_SHIELD) {
     Serial.println("WiFi not present");
     // don't continue:
     while (true);
  }


// ADD THIS TO LOOP??????????????
// MAKE ITS OWN FUNCTION???????

  // attempt to connect to Wifi network:
  while ( status != WL_CONNECTED) {
    Serial.print("Attempting to connect to SSID: ");
    Serial.println(ssid);
    // Connect to WPA/WPA2 network. Change this line if using open or WEP network:
     status = WiFi.begin(ssid, pass);

    // wait 8 seconds for connection:
    delay(8000);
  }

  Serial.println("Connected to wifi");
  printWifiStatus();


}


void loop(){

// Add code to check to see if wifi is still on. If not, stop and keep trying to connect

// WAKE UP CAMERA FROM SLEEP AND CONNECT
CameraInitiate();

// Add code to make sure that camera recognized (status 31)


// START RECORDING
StartRecording();

delay(5000);

// STOP RECORDING
StopRecording();

delay(5000);

}


void StartRecording(){
  Serial.print("connecting to ");
  Serial.println(host);

  if (!client.connect("10.5.5.9", httpPort)) {
    Serial.println("connection failed");
    return;
  }

  //Command for starting recording
  String StartUrl = "/gp/gpControl/command/shutter?p=1";
  Serial.print("Requesting URL: ");
  Serial.println(StartUrl);
  client.print(String("GET ") + StartUrl + " HTTP/1.1\r\n" +
  "Host: " + host + "\r\n" +
  "Connection: close\r\n\r\n");
  Serial.println("Recording");
}



void StopRecording(){
  Serial.print("connecting to ");
  Serial.println(host);
  
  if (!client.connect("10.5.5.9", httpPort)) {
    Serial.println("connection failed");
    return;
  }

  //Command for stopping recording
  String StopUrl = "/gp/gpControl/command/shutter?p=0";
  Serial.print("Requesting URL: ");
  Serial.println(StopUrl);
  client.print(String("GET ") + StopUrl + " HTTP/1.1\r\n" +
  "Host: " + host + "\r\n" +
  "Connection: close\r\n\r\n");
  Serial.println("Stopped");
}



// FUNCTION TO WAKE UP THE CAMERA

void CameraInitiate(){

  //Begin UDP communication
  Udp.begin(localPort);

  //Send the magic packet to wake up the GoPro out of sleep
  delay(2000);
  SendMagicPacket();
  delay(5000);  

  // Absolutely necessary to flush port of UDP junk for Wifi client communication
  Udp.flush();
  delay(1000);

  //Stop UDP communication
  Udp.stop();
  delay(1000);

}


// Function to create and send magic packet
// Taken and translated from here:
// https://www.logicaprogrammabile.it/wol-accendere-computer-arduino-wake-on-lan/

void SendMagicPacket(){

  //Create a 102 byte array
  byte magicPacket[102];

  // Variables for cycling through the array
  int Cycle = 0, CycleMacAdd = 0, IndexArray = 0;

  // This for loop cycles through the array
  for( Cycle = 0; Cycle < 6; Cycle++){

    // The first 6 bytes of the array are set to the value 0xFF
    magicPacket[IndexArray] = 0xFF;

    // Increment the array index
    IndexArray++;
  }

  // Now we cycle through the array to add the GoPro address
  for( Cycle = 0; Cycle < 16; Cycle++ ){
    //eseguo un Cycle per memorizzare i 6 byte del
    //mac address
    for( CycleMacAdd = 0; CycleMacAdd < 6; CycleMacAdd++){
      
      magicPacket[IndexArray] = remote_MAC_ADD[CycleMacAdd];
      
      // Increment the array index
      IndexArray++;
    }
  }

  //The magic packet is now broadcast to the GoPro IP address and port
  Udp.beginPacket(broadCastIp, wolPort);
  Udp.write(magicPacket, sizeof magicPacket);
  Udp.endPacket();

}



void printWifiStatus() {
  // print the SSID of the network you're attached to:
  Serial.print("SSID: ");
  Serial.println(WiFi.SSID());

  // print your WiFi shield's IP address:
  IPAddress ip = WiFi.localIP();
  Serial.print("IP Address: ");
  Serial.println(ip);

  // print the received signal strength:
  long rssi = WiFi.RSSI();
  Serial.print("signal strength (RSSI):");
  Serial.print(rssi);
  Serial.println(" dBm");
}
Add Tip

Шаг 7. Получение обновлений статуса GoPro

Вы можете получать обновления статуса GoPro, используя эту ссылку:

http://10.5.5.9/gp/gpControl/status

Когда эта ссылка вызывается, она предоставляет объект JSON, который может быть проанализирован с использованием этого руководства.

Самый простой способ увидеть это - подключиться к Wi-Fi сети GoPro с вашим компьютером и загрузить вышеуказанную ссылку с помощью веб-браузера.

Он вернет что-то похожее на:

{"status"{"1":1,"2":2,"3":0,"4":0,"6":0,"8":0,"9":0,"10":0,"13":0,"14":0,"15":0,"16":0,"17":1,"19":0,"20":0,"21":0,"22":0,"23":0,"24":0,"26":0,"27":0,"28":82,"29":"","30":"","31":0,"32":0,"33":0,"34":2796,"35":1917,"36":0,"37":1,"38":0,"39":1,"40":"%12%05%13%0C%04%0E","41":0,"42":0,"43":0,"44":0,"45":0,"46":1,"47":1,"48":1,"49":0,"54":15476384,"55":1,"56":0,"57":3927,"58":0,"59":0,"60":500,"61":2,"62":0,"63":0,"64":0,"69":1,"71":12,"72":19,"73":20,"74":0}, "settings":{"1":0,"2":1,"3":8,"4":0,"5":0,"6":1,"7":1,"8":1,"9":0,"10":0,"11":0,"12":0,"13":1,"14":0,"15":4,"16":0,"17":4,"18":1,"19":0,"20":0,"21":1,"22":0,"23":0,"24":0,"25":0,"26":4,"27":0,"28":4,"29":5,"30":0,"31":0,"32":3601,"33":0,"34":0,"35":0,"36":0,"37":0,"38":0,"39":4,"40":0,"41":13,"42":8,"43":0,"44":8,"45":8,"46":0,"47":0,"48":0,"52":1,"54":1,"57":0,"58":1,"59":6,"60":8,"61":1,"62":2500000,"63":7,"64":4,"65":0,"66":0,"67":0,"68":0,"69":1,"70":0,"71":0,"73":0,"74":0,"75":3,"76":3,"78":1,"84":0,"85":0,"86":1,"87":40,"89":12,"91":0,"92":12,"95":1,"96":0}}

На этом пока всё. Будьте внимательны и осторожны при работе с GoPro и Ардуино, проверяйте всё много раз, прежде чем запустить что-то.

Ардуино+