AutomaticCameraControl: Difference between revisions
Imdacrocker (talk | contribs) (Added a section for the Hero4 control) |
|||
Line 488: | Line 488: | ||
* The POST command is repeated the number of times specified by reps. This is because during testing the startRecording was not entirely reliable. The camera somehow missed the command. | * The POST command is repeated the number of times specified by reps. This is because during testing the startRecording was not entirely reliable. The camera somehow missed the command. | ||
* The trigger condition is set to use bit 6 of the CAN channel 77AB2. This signal comes from a switch on the dashboard wired to an ECU, which then sends switch status on the CAN to which the RaceCapture/Track MK2 is connected. Modify accordingly if you have a similar switch, otherwise comment this out and uncomment the getGpsSpeed() line, altering the autoStart and autoStop thresholds accordingly. | * The trigger condition is set to use bit 6 of the CAN channel 77AB2. This signal comes from a switch on the dashboard wired to an ECU, which then sends switch status on the CAN to which the RaceCapture/Track MK2 is connected. Modify accordingly if you have a similar switch, otherwise comment this out and uncomment the getGpsSpeed() line, altering the autoStart and autoStop thresholds accordingly. | ||
=Experimental GoPro Hero4 Control= | |||
The GoPro Hero4 has proven to be a cheap and reliable camera in many uses, and motorsports is no exception. | |||
Limited testing has been done using custom Lua code to use UDP camera commands | |||
This has been shown to work with newer cameras as well, up through Hero8, but no field testing has been done. | |||
==Customization== | |||
You will want to edit the MAC address to match the camera you are pairing. Edit this line: | |||
<pre> | |||
local mac = string.char(0xd4, 0xd9, 0x19, 0x99, 0xc4, 0xef) -- This is the mac addres of my camera, d4:d9:19:99:c4:ef | |||
</pre> | |||
So if your MAC address is d4:d9:27:87:b6:e5, change the line to: | |||
<pre> | |||
local mac = string.char(0xd4, 0xd9, 0x27, 0x87, 0xb6, 0xe5) | |||
</pre> | |||
==Setup== | |||
To connect the camera to the RaceCapture, first turn on the RaceCapture. Then, from the GoPro, connect a new Smart Remote. | |||
The RaceCapture emulates the GoPro smart remote | |||
Once connected, you can confirm connection by looking at the virtual channel "Camera" | |||
*0 indicates not connected | |||
*1 indicates connected and not recording | |||
*2 indicates connected and recording | |||
Once paired, when the RaceCapture is shut down, you can turn the Camera's Wifi on. When the RaceCapture powers on, it should automatically turn on the camera. | |||
==Use== | |||
This code is set up to watch the isLogging() value, and trigger camera recording when logging begins. | |||
==Lua Code== | |||
<pre> | |||
local c = addChannel("Camera", 1, 0, 0, 2) | |||
lastResponse = getUptime() | |||
lastKeepAlive = getUptime() | |||
lastRequest = getUptime() | |||
function sendRaw(val) | |||
for i = 1, #val do | |||
local c = string.sub(val, i, i) | |||
writeCSer(5, string.byte(c)) | |||
end | |||
end | |||
function sendAt(val) | |||
sendRaw(val) | |||
writeCSer(5, 13) | |||
writeCSer(5, 10) | |||
end | |||
function sendCommand(command, connection) | |||
sendAt('AT+CIPSEND=' .. connection .. ',' .. string.sub(#command, 1, -3)) | |||
pi() | |||
sendRaw(command) | |||
pi() | |||
end | |||
function pi() -- process incoming, reads from serial character by character | |||
local char = readCSer(5, 100) | |||
if char == nil then | |||
return | |||
end | |||
local line = '' | |||
while (char ~= nil) do | |||
line = line .. string.char(char) | |||
if string.find(line, '+IPD,') then -- This means incoming packet | |||
readCSer(5, 100) | |||
char = readCSer(5, 100) | |||
char = readCSer(5, 100) | |||
local length = '' | |||
while char ~= 58 do | |||
if char == nil then | |||
return | |||
end | |||
length = length .. string.char(char) | |||
char = readCSer(5, 100) | |||
end | |||
local packet = '' | |||
if tonumber(length) == nil then | |||
else | |||
for i = 1, tonumber(length) do | |||
packet = packet .. string.sub(readCSer(5, 100), 1, -3) .. ' ' | |||
end | |||
lastResponse = getUptime() | |||
if getChannel(c) == 0 then | |||
setChannel(c, 1) | |||
end | |||
if packet == '95 71 80 72 68 95 58 48 58 48 58 50 58 1 ' then -- This is the KeepAlive response | |||
if getChannel(c) == 0 then | |||
setChannel(c, 1) | |||
end | |||
elseif packet == '0 0 0 0 0 0 0 0 0 0 0 115 116 0 0 0 0 0 0 0 ' then -- This response means camera is on and not recording | |||
setChannel(c, 1) | |||
elseif packet == '0 0 0 0 0 0 0 0 0 0 0 115 116 0 0 1 0 1 0 0 ' then -- This response means the camera IS recording | |||
setChannel(c, 2) | |||
elseif packet == '0 0 0 0 0 0 0 0 0 0 0 115 116 1 0 0 0 0 0 0 ' then -- This means the camera is off | |||
setChannel(c, 0) | |||
end | |||
return | |||
end | |||
end | |||
char = readCSer(5, 100) | |||
end | |||
end | |||
sendAt('AT+RST') -- Reset ESP8266 | |||
pi() | |||
sendAt('AT+CWMODE_CUR=2') -- Set as an access point | |||
pi() | |||
sendAt('AT+CWSAP_CUR="HERO-RC-000000","",1,0') -- This is the SSID to emulate a remote. The last 6 need to match the below piece | |||
pi() | |||
sendAt('AT+CIPAPMAC_CUR="d8:96:85:00:00:00"') -- Remote MAC address all start with the same 3 sets, then you can use any set. all 0's work | |||
pi() | |||
sendAt('AT+CIPAP_CUR="10.71.79.1"') -- The remote IP | |||
pi() | |||
sendAt('AT+CIPMUX=1') -- Setting to accept multiple connections | |||
pi() | |||
sleep(1000) | |||
sendAt('AT+CIPSTART=0,"UDP","255.255.255.255",9') -- Set up a connection to the subnet for the WOL | |||
pi() | |||
sendAt('AT+CIPSTART=1,"UDP","10.71.79.2",8484,8383') -- Set up a connection to the camera | |||
pi() | |||
setTickRate(10) | |||
function onTick() | |||
-- checkCamera() | |||
if (getUptime() - lastResponse) > 5000 then -- If there has been no response for 5 seconds, start sending a WOL packet | |||
setChannel(c, 0) -- Set camera to not connected | |||
local mac = string.char(0xd4, 0xd9, 0x19, 0x99, 0xc4, 0xef) -- This is the mac addres of my camera, d4:d9:19:99:c4:ef | |||
local packet = string.char(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF) -- The opening of the packet is a null packet | |||
for i = 1, 16 do | |||
packet = packet .. mac -- And then the MAC address 16 times | |||
end | |||
sendCommand(packet, '0') | |||
end | |||
if isLogging() == 0 and getChannel(c) == 2 then -- If we are not logging, but the camera is recording, stop the camera | |||
sendCommand(string.char(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x53, 0x48, 0x00), '1') -- Stop camera | |||
setChannel(c, 1) | |||
end | |||
if isLogging() ~= 0 and getChannel(c) == 1 then -- If we ARE logging, and not recording, then record | |||
sendCommand(string.char(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x53, 0x48, 0x02), '1') -- Start camera | |||
setChannel(c, 2) | |||
end | |||
if (getUptime() - lastKeepAlive) > 1500 then -- Send a keep alive packet every 1.5 seconds | |||
sendAt('AT+CIPSEND=1,22') | |||
pi() | |||
sendRaw('_GPHD_:0:0:2:0.000000\n') -- This is the actual keep alive command | |||
pi() | |||
lastKeepAlive = getUptime() | |||
end | |||
if (getUptime() - lastRequest) > 5000 then -- Send a status request every 5 seonds | |||
sendCommand(string.char(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x73, 0x74), '1') -- This is the actual request command | |||
lastRequest = getUptime() | |||
end | |||
pi() -- Process incoming every tick | |||
end | |||
</pre> |
Revision as of 21:03, 15 November 2022
Automatic Camera Control
Introduction
This guide shows you how to enable automatic start / stop control of WiFi enabled cameras, such as GoPro using RaceCapture or PodiumConnect.
How it works
Most action cameras offer a WiFi interface for remote control. GoPro is one such camera, and allows shutter control via the WiFi interface, which RaceCapture or PodiumConnect can leverage for automatic triggering.
Currently supported versions of RaceCapture hardware
- PodiumConnect
- RaceCapture/Apex
- RaceCapture/Pro MK3
- RaceCapture/Track MK1 and MK2
- RaceCapture/Pro MK2 with external WiFi add-on (see below)
Currently supported cameras
- GoPro Hero 2/3
- GoPro Hero 4/5 (experimental)
- Garmin Virb Ultra 30 (experimental)
Note, We recommend GoPro 2/3 due to stability / reliability issues seen with the later GoPro devices.
Additional Camera support will be added with future firmware releases.
Overview
RaceCapture or PodiumConnect is configured so it's WiFi client connects to the camera's access point using its SSID and WiFi password.
When RaceCapture/PodiumConnect triggers the camera based on a sensor threshold such as speed, RPM or other value, it sends a command to the camera to start recording. When the sensor falls below the threshold, the corresponding command is sent to stop the recording.
Simultaneous WiFi connection with the RaceCapture App
Since the WiFi client feature is used on RaceCapture/PodiumConnect to connect to the camera, the Access Point remains available for the RaceCapture app to connect via WiFi, as usual. Or, via Bluetooth, if supported by the RaceCapture system.
Setting up Automatic Camera Control
Applies to
- PodiumConnect
- RaceCapture/Apex
- RaceCapture/Pro MK3
- RaceCapture/Track MK1 and MK2
Requirements
- Firmware 2.13.0 or higher
Set up WiFi client
Navigate to Setup / Wireless and ensure:
- WiFi is turned ON
- WiFi client is turned ON
- Camera SSID and password are specified in the WiFi client settings.
Set up Automatic Control
Navigate to Setup / Automatic Control and ensure:
- The desired sensor channel trigger is selected (Speed is the default)
- Your start / stop and time thresholds are configured
- Camera Control is turned ON and you have your camera model selected.
Write Settings
Write the settings back to RaceCapture by pressing the Write button under Setup.
Testing
Turn on the camera and ensure the camera has it's WiFi interface enabled.
Power up RaceCapture, connect the RaceCapture app and verify the WiFi client is connected under the System Status page. File:Verifying wifi client connected.png
It may take several seconds for the client to connect. If not, re-check the camera's SSID/password, and ensure WiFi is enabled on the camera.
- Note: On GoPros, the Camera must be in 'App mode' with WiFi enabled.
Once it is connected to the camera, you can test the camera by triggering the configured camera's threshold.
- Tip: For static testing, you can configure the camera control to one of the Accelerometer channels, such as AccelZ and trigger by inverting RaceCapture. Or, use RPM, battery voltage or similar.
RaceCapture/Pro MK2
While the automatic camera control firmware feature is not available for RaceCapture/Pro MK2, it can still be controlled via a Lua script.
When WiFi is enabled on your GoPro camera it creates a network that other devices can connect to. A WiFi enabled version of RaceCapture/Pro can connect to this network and issue the appropriate commands to control various camera functions - in this case, starting and stopping video recording.
Starting and stopping the GoPro can be controlled by a variety of means: speed, RPM or based on other sensor data, enabled by a Lua Script running on RaceCapture/Pro.
This guide focuses on using GPS speed to trigger the camera; for triggering on other sensors see the Lua scripting guide as a reference for what other sensor data is available.
Notes
- Currently, the WiFi module can only be used to enable GoPro triggering.
- If running firmware version 2.10.x or higher To use this script, you must disable the built-in WiFi control, or else it will take over the connection and block the script from running.
- Future versions of RaceCapture firmware and app will allow built-in firmware control of GoPro cameras, which will eliminate the need for this script.
Requirements
- RaceCapture/Pro MK2 running firmware 2.9.1 or higher
- RaceCapture/Pro WiFi module
- WiFi enabled GoPro Hero camera, with WiFi activated
- GPS Connectivity (for speed measurement)
Steps
Configure your GoPro
Using the GoPro app, configure the WiFi network, making a note of the network name (SSID) and password.
Connect the WiFi module
Connect the RaceCapture/Pro WiFi module to the outermost (Auxiliary) port of RaceCapture/Pro.
- When powered up, you should see the power LED illuminate.
- This port is to the right of the Bluetooth Port.
- The WiFi module does not interfere with the operation of the Bluetooth module.
Enable Lua script for GoPro connectivity
Customize the Lua script shown at the bottom with the GoPro's WiFi network name (SSID) and password, then copy and paste the Lua script shown at the bottom into the scripting window of your RaceCapture/Pro.
Steps:
- Connect RaceCapture/Pro to the RaceCapture app and read the current configuration.
- Copy the Lua script into the Scripting window:
- Ensure the script window is first blank by removing the default script by deleting the text in the window.
- Note: If you have an existing script you want to keep, you will need to blend the camera functionality with your existing script. How to do this is beyond the scope of this guide; see the Lua Scripting Guide for more information.
- Copy the script into the window by using the ctrl-v keyboard shortcut.
- Ensure the script window is first blank by removing the default script by deleting the text in the window.
- Write the configuration back to RaceCapture/Pro.
Bench testing
Once the Lua script is written to RaceCapture/Pro, it will attempt to connect to the network created by the GoPro camera. Once connected, it will be ready to issue start / stop commands to the camera.
Before road testing, ensure RaceCapture/Pro can connect to the GoPro's WiFi network by observing the messages in the window below the script.
- Tip 1: Touch or click the Poll Log to see the current message in the RaceCapture/Pro log
- Tip 2: To restart the Lua script, touch or click the 'Restart' button.
Road testing
Mount the GoPro in the car as usual and power up RaceCapture/Pro, waiting for GPS achieve a lock.
- Drive carefully above the speed threshold and observe the GoPro - you should hear and see the familiar beep and red light activate, just as if you manually started recording using the shutter button on the camera.
- When you drop below the threshold, the GoPro should stop recording.
As RaceCapture/Pro starts and stops the camera, you will see the following information in the log:
[GoProWiFi] start GoPro [GoProWiFi] stop GoPro
Troubleshooting
If RaceCapture/Pro cannot control the camera, check the following:
- GoPro WiFi network name (SSID) and password: Ensure the name and password currently in the script matches how your GoPro was configured.
- Enable WiFi on the GoPro: The blue LED on the GoPro should be blinking periodically
- RaceCapture/Pro WiFi module connection: Ensure the module is plugged into the outermost RJ11 port and the green LED is illuminated.
- Verify WiFi connection: Ensure RaceCapture/Pro can connect to the GoPro WiFi network. You should see the following messages in the log upon power-up:
[lua] Successfully loaded script. [GoProWiFi] initializing [GoProWiFi] ready for GoPro
If RaceCapture/Pro cannot connect to the GoPro's network you will see this in the log:
[GoProWiFi] initializing [GoProWiFi] could not connect to GoPro [GoProWiFi] initializing [GoProWiFi] could not connect to GoPro [GoProWiFi] initializing [GoProWiFi] could not connect to GoPro [GoProWiFi] initializing
Lua Script for GoPro
The following Lua Script enables WiFi control of your GoPro camera.
Customization
You will need to edit the following fields at the minimum, located at the top of the script:
Required
- GoPro WiFi password: Specify the WiFi password used for the GoPro WiFi adapter
- GoPro SSID: Specify the GoPro WiFi network name (SSID)
Optional
- goproStart: Change this if you want to start recording at a different threshold.
- goproStop: Change this if you want to stop recording at a different threshold. Ensure this is less than the start trigger
- tickRate: Adjust this to update how often you want RaceCapture/Pro to perform a start/stop check. Value is in Hz. If uncertain, leave this alone
- debug: If things aren't working as expected you can set this to 1 to see the conversation between the WiFi module and the GoPro.
- This information shows up in the log window below the script window - check the box Poll log to see this information.
--Specify your GoPro wifi password here goproPwd = '12345678' --Specify your GoPro SSID here goproSsid = 'aslhero1' --Speed threshold to start recording goproStart = 10 --Speed threshold to stop recording goproStop = 5 --How fast we check, in Hz tickRate = 10 --Set this to 1 to log communications between RCP & WiFi debug = 0 ----------------------------- --DO NOT EDIT BELOW ----------------------------- --the serial port where the WiFi is connected port = 4 --indicates wifiStatus --0 = not init, 1 = init sent, 2 = got IP, 3 = ready wifiStatus = 0 lastInitTime = 0 initTimeout = 20000 function logMsg(msg) println('[GoProWiFi] ' ..msg) end function sendCrlf() writeCSer(port, 13) writeCSer(port, 10) end function sendRaw(val) for i=1, #val do local c = string.sub(val, i, i) writeCSer(port, string.byte(c)) end end function sendAt(val) if debug == 1 then logMsg('send: ' ..val) end sendRaw(val) sendCrlf() end function toInt(val) return string.sub(val, 1, -3) end function httpGet(url) sendAt('AT+CIPSTART="TCP","10.5.5.9",80') sleep(500) local crlf = string.char(13) ..string.char(10) local get = 'GET ' ..url ..' HTTP/1.0' ..crlf ..crlf sendAt('AT+CIPSEND=' ..toInt(#get)) sleep(100) sendRaw(get) sleep(100) sendAt("AT+CIPCLOSE") end function sendGoProShutter(cmd) httpGet('/bacpac/SH?t=' ..goproPwd ..'&p=%' ..cmd) end function startGoPro() logMsg('start GoPro') sendGoProShutter('01') end function stopGoPro() logMsg('stop GoPro') sendGoProShutter('00') end recording = 0 function initWiFi() logMsg('initializing') sendAt('AT+RST') sleep(2000) sendAt('AT+CWMODE_CUR=1') sleep(1000) sendAt('AT+CWJAP_CUR="' ..goproSsid ..'","' ..goproPwd ..'"') wifiStatus = 1 end function processIncoming() local line = readSer(port, 100) if line ~= '' and debug == 1 then print(line) end if string.match(line, 'WIFI GOT IP') then wifiStatus = 2 end if wifiStatus == 2 and string.match(line, 'OK') then wifiStatus = 3 logMsg('ready for GoPro') end end function checkGoPro() if wifiStatus == 0 then initWiFi() lastInitTime = getUptime() return end if wifiStatus == 1 and getUptime() > lastInitTime + initTimeout then logMsg('could not connect to GoPro') wifiStatus = 0 end processIncoming() if wifiStatus ~= 3 then return end trigger = getGpsSpeed() if recording == 0 and trigger > goproStart then startGoPro() recording = 1 end if recording == 1 and trigger < goproStop then stopGoPro() recording = 0 end end function onTick() checkGoPro() end setTickRate(tickRate)
Lua Script for Garmin Virb
The following Lua Script enables WiFi control of your Garmin Virb camera using the Garmin Camera Network Services API. Not all commands in the API may work. Use commandList (via Postman) to determine which API commands are supported by your Garmin Virb camera.
The Garmin Virb always uses 192.168.0.1 HTTP port ( 80 ).
NOTE: this Lua script is different than the GoPro script above in that Garmin uses POST commands instead of GET commands.
For a more detailed explanation, see How to send HTTP POST request via Lua Script?
It may be possible to control other WiFi devices by altering the POST command accordingly. e.g. instead of sending httpPost arguments {"command":"startRecording"} substitute this with the commands specified by the device API. Be sure to adjust the server host IP address if different than the Garmin standard.
Customization
You will need to edit the following fields at the minimum, located at the top of the script:
Required
- Ssid: Specify the WiFi network name (SSID)
- Pwd: Specify the WiFi password
Optional
- Port: 5 is the WiFi port for the RaceCapture/Track MK2. Change according to Port mapping
- autoStart: Change this if you want to start recording at a different threshold.
- autoStop: Change this if you want to stop recording at a different threshold.
- debug: If things aren't working as expected you can set this to 1 to see the conversation between the WiFi module and the GoPro.
- This information shows up in the log window below the script window - check the box Poll log to see this information.
setTickRate(10) --TickRate is in Hz --configure WiFi serial port port = 5 initSer(port,115200,8,0,1) --Specify client SSID here Ssid = 'VIRB-4615' --Specify client wifi password here Pwd = '12345678' --Set this to 1 to log communications between RCP & WiFi debug = 0 --initialize variables trigger = 0 recording = 0 --define constants autoStart = 0 --Threshold to start recording autoStop = 1 --Threshold to stop recording ------WiFi Code-------------- --DO NOT EDIT BELOW ----------------------------- --indicates wifiStatus --0 = not init, 1 = init sent, 2 = got IP, 3 = ready wifiStatus = 0 lastInitTime = 0 initTimeout = 20000 reps = 3 --number of times to repeat command function logMsg(msg) println('[WiFi] ' ..msg) end function sendCrlf() writeCSer(port, 13) writeCSer(port, 10) end function sendRaw(val) for i=1, #val do local c = string.sub(val, i, i) writeCSer(port, string.byte(c)) end end function sendAt(val) if debug == 1 then logMsg('send: ' ..val) end sendRaw(val) sendCrlf() end function toInt(val) return string.sub(val, 1, -3) end function httpPost(cmd) sendAt('AT+CIPSTART="TCP","192.168.0.1",80') sleep(500) local crlf = string.char(13) ..string.char(10) local post = 'POST /virb HTTP/1.1\r\nHost: 192.168.0.1\r\nAccept: */*\r\nContent-Length: ' ..toInt(#cmd)..'\r\nContent-Type: application/x-www-form-urlencoded\r\n\r\n' ..cmd ..'\r\n' ..crlf ..crlf sendAt('AT+CIPSEND=' ..toInt(#post)) sleep(100) sendRaw(post) if debug == 1 then println(post) end sleep(100) sendAt('AT+CIPCLOSE') end function initWiFi() logMsg('initializing') sendAt('AT+RST') sleep(2000) sendAt('AT+CWMODE_CUR=1') sleep(1000) sendAt('AT+CWJAP_CUR="' ..Ssid ..'","' ..Pwd ..'"') wifiStatus = 1 end function processIncoming() local line = readSer(port, 100) if line ~= '' and debug == 1 then print(line) end if string.match(line, 'WIFI GOT IP') or string.match(line, 'WIFI CONNECTED') then wifiStatus = 2 end if wifiStatus == 2 and string.match(line, 'OK') then wifiStatus = 3 logMsg('ready for WiFi') end end function checkWiFi() if wifiStatus == 0 then initWiFi() lastInitTime = getUptime() return end if wifiStatus == 1 and getUptime() > lastInitTime + initTimeout then logMsg('could not connect to WiFi') wifiStatus = 0 end processIncoming() if wifiStatus ~= 3 then return end --trigger = getGpsSpeed() trigger = bit.rshift(bit.band(getChannel("77AB2"),0x40),6) --trigger = 1 if recording == 0 and trigger > autoStart then for i=1,reps,1 do httpPost('{"command":"startRecording"}') end recording = 1 end if recording == 1 and trigger < autoStop then for i=1,reps,1 do httpPost('{"command":"stopRecording"}') end recording = 0 end end function onTick() checkWiFi() --println('trigger value: ' ..trigger) --println('recording status: ' ..recording) if debug ==1 then println("WiFi Status: " ..wifiStatus) end end
A few comments:
- The POST command is repeated the number of times specified by reps. This is because during testing the startRecording was not entirely reliable. The camera somehow missed the command.
- The trigger condition is set to use bit 6 of the CAN channel 77AB2. This signal comes from a switch on the dashboard wired to an ECU, which then sends switch status on the CAN to which the RaceCapture/Track MK2 is connected. Modify accordingly if you have a similar switch, otherwise comment this out and uncomment the getGpsSpeed() line, altering the autoStart and autoStop thresholds accordingly.
Experimental GoPro Hero4 Control
The GoPro Hero4 has proven to be a cheap and reliable camera in many uses, and motorsports is no exception.
Limited testing has been done using custom Lua code to use UDP camera commands
This has been shown to work with newer cameras as well, up through Hero8, but no field testing has been done.
Customization
You will want to edit the MAC address to match the camera you are pairing. Edit this line:
local mac = string.char(0xd4, 0xd9, 0x19, 0x99, 0xc4, 0xef) -- This is the mac addres of my camera, d4:d9:19:99:c4:ef
So if your MAC address is d4:d9:27:87:b6:e5, change the line to:
local mac = string.char(0xd4, 0xd9, 0x27, 0x87, 0xb6, 0xe5)
Setup
To connect the camera to the RaceCapture, first turn on the RaceCapture. Then, from the GoPro, connect a new Smart Remote.
The RaceCapture emulates the GoPro smart remote
Once connected, you can confirm connection by looking at the virtual channel "Camera"
- 0 indicates not connected
- 1 indicates connected and not recording
- 2 indicates connected and recording
Once paired, when the RaceCapture is shut down, you can turn the Camera's Wifi on. When the RaceCapture powers on, it should automatically turn on the camera.
Use
This code is set up to watch the isLogging() value, and trigger camera recording when logging begins.
Lua Code
local c = addChannel("Camera", 1, 0, 0, 2) lastResponse = getUptime() lastKeepAlive = getUptime() lastRequest = getUptime() function sendRaw(val) for i = 1, #val do local c = string.sub(val, i, i) writeCSer(5, string.byte(c)) end end function sendAt(val) sendRaw(val) writeCSer(5, 13) writeCSer(5, 10) end function sendCommand(command, connection) sendAt('AT+CIPSEND=' .. connection .. ',' .. string.sub(#command, 1, -3)) pi() sendRaw(command) pi() end function pi() -- process incoming, reads from serial character by character local char = readCSer(5, 100) if char == nil then return end local line = '' while (char ~= nil) do line = line .. string.char(char) if string.find(line, '+IPD,') then -- This means incoming packet readCSer(5, 100) char = readCSer(5, 100) char = readCSer(5, 100) local length = '' while char ~= 58 do if char == nil then return end length = length .. string.char(char) char = readCSer(5, 100) end local packet = '' if tonumber(length) == nil then else for i = 1, tonumber(length) do packet = packet .. string.sub(readCSer(5, 100), 1, -3) .. ' ' end lastResponse = getUptime() if getChannel(c) == 0 then setChannel(c, 1) end if packet == '95 71 80 72 68 95 58 48 58 48 58 50 58 1 ' then -- This is the KeepAlive response if getChannel(c) == 0 then setChannel(c, 1) end elseif packet == '0 0 0 0 0 0 0 0 0 0 0 115 116 0 0 0 0 0 0 0 ' then -- This response means camera is on and not recording setChannel(c, 1) elseif packet == '0 0 0 0 0 0 0 0 0 0 0 115 116 0 0 1 0 1 0 0 ' then -- This response means the camera IS recording setChannel(c, 2) elseif packet == '0 0 0 0 0 0 0 0 0 0 0 115 116 1 0 0 0 0 0 0 ' then -- This means the camera is off setChannel(c, 0) end return end end char = readCSer(5, 100) end end sendAt('AT+RST') -- Reset ESP8266 pi() sendAt('AT+CWMODE_CUR=2') -- Set as an access point pi() sendAt('AT+CWSAP_CUR="HERO-RC-000000","",1,0') -- This is the SSID to emulate a remote. The last 6 need to match the below piece pi() sendAt('AT+CIPAPMAC_CUR="d8:96:85:00:00:00"') -- Remote MAC address all start with the same 3 sets, then you can use any set. all 0's work pi() sendAt('AT+CIPAP_CUR="10.71.79.1"') -- The remote IP pi() sendAt('AT+CIPMUX=1') -- Setting to accept multiple connections pi() sleep(1000) sendAt('AT+CIPSTART=0,"UDP","255.255.255.255",9') -- Set up a connection to the subnet for the WOL pi() sendAt('AT+CIPSTART=1,"UDP","10.71.79.2",8484,8383') -- Set up a connection to the camera pi() setTickRate(10) function onTick() -- checkCamera() if (getUptime() - lastResponse) > 5000 then -- If there has been no response for 5 seconds, start sending a WOL packet setChannel(c, 0) -- Set camera to not connected local mac = string.char(0xd4, 0xd9, 0x19, 0x99, 0xc4, 0xef) -- This is the mac addres of my camera, d4:d9:19:99:c4:ef local packet = string.char(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF) -- The opening of the packet is a null packet for i = 1, 16 do packet = packet .. mac -- And then the MAC address 16 times end sendCommand(packet, '0') end if isLogging() == 0 and getChannel(c) == 2 then -- If we are not logging, but the camera is recording, stop the camera sendCommand(string.char(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x53, 0x48, 0x00), '1') -- Stop camera setChannel(c, 1) end if isLogging() ~= 0 and getChannel(c) == 1 then -- If we ARE logging, and not recording, then record sendCommand(string.char(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x53, 0x48, 0x02), '1') -- Start camera setChannel(c, 2) end if (getUptime() - lastKeepAlive) > 1500 then -- Send a keep alive packet every 1.5 seconds sendAt('AT+CIPSEND=1,22') pi() sendRaw('_GPHD_:0:0:2:0.000000\n') -- This is the actual keep alive command pi() lastKeepAlive = getUptime() end if (getUptime() - lastRequest) > 5000 then -- Send a status request every 5 seonds sendCommand(string.char(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x73, 0x74), '1') -- This is the actual request command lastRequest = getUptime() end pi() -- Process incoming every tick end