Hello, All. I’m new to DIY drones community
I built my first quadcopter using Pixhawk 2.4.8 and the Copter V4.2.1 firmware and I’m using a Raspberry Pi 4 as a companion computer.
My aspiration
I am willing to take geotaged photos with an Arducam camera connected to the RPi while completing a waypoint mission autonomously.
Following ae the hardware option available for me:
Pixhawk 2.4.8
Respberry pi 4
Arducam 16mp autofocus
Objective:
Trigger Arducam automatically for taking geotagged photos while the drone is on a waypoint mission.
Is there any lead / solution that i can follow ?
Could some one please point me in right direction.
Thank you.
Hi Birendra,
It has been a while since applying these workflows, so there may be a error in my description of the process, but I think these are two approaches that may inform your efforts.
I think that you are wanting to create a mission using the survey grid tool. this will allow you to define the camera parameters to achieve the ground image you want. This tool will also allow for setting up the camera trigger for optimizing for 3D reconstruction (image sidelap and overlap. Camera triggers can be set as a high pin from one of the Autopilot output pins. You should, in theory, be able to trigger your Pi cam using this signal.
Alternatively you can set the camera trigger to a distance parameter and the signal will be sent at that interval or distance. I think this approach will work (if enabled) during a standard mission.
You can then use the geotagging tool in mission planner to correlate the cam messages to the images, creating a separate geotagged folder of the images.
Best of Luck,
Sean
A few years ago I used an RPI+RPI camera to capture images as part of the TAP-J team’s entry in the Japan Innovation Challenge search and rescue competition. This included capturing the autopilot’s location and embedding it into JPEG images. The code we used is here (I think).
After a lot of beating around the bush, I was able to capture the pictures and geotag them onboard.
Still had some issues in reading the gps data at the same time while triggering the camera and geotagging the images. I was also not sure about the accuracy. It would take a lot of effort to write fully optimised code for it.
Instead it would be easy and feasible to use Airpixel geotagger which has way more features than just geotagging, it is light weight, superfast etc, you can read about it in docs.
Assuming you have successful connection between Rpi and Pixhawk.
You can use below code as template, install python, exifread, dronekit.
import asyncio
import os
from datetime import datetime
import exifread
import dronekit
import time
import shutil
from picamera2 import Picamera2
# Define the target folder for geotagged images
TARGET_FOLDER = "/home/pi/Desktop/images/"
#1 Initialize PiCamera
picam2 = Picamera2()
#Create a new object, camera_config and use it to set the still image resolution (main) to 1920 x 1080. and a “lowres” image with a size of 640 x 480. This lowres image is used as the preview image when framing a shot.
camera_config = picam2.create_still_configuration(main={"size": (1920, 1080)}, lores={"size": (640, 480)}, display="lores")
#Load the configuration.
picam2.configure(camera_config)
#2 Connect to the drone and wait for GPS fix
print("Connecting to vehicle...")
vehicle = dronekit.connect('/dev/ttyAMA0', baud=57600)
print("Waiting for GPS fix...")
while not vehicle.gps_0.fix_type:
pass
print("GPS fix obtained.")
# Define the capture_photo function
async def capture_photo():
filename = datetime.now().strftime("%Y%m%d_%H%M%S.jpg")
temp_file = "/run/shm/{}".format(filename) # Use the ramdisk for faster I/O
picam2.start()
#Pause the code for two seconds.
time.sleep(1)
#Capture an image and save it as test.jpg.
picam2.capture_file(temp_file)
return temp_file
# Define the get_gps_data function
async def get_gps_data():
#return (vehicle.location.global_frame.lat,
# vehicle.location.global_frame.lon,
# vehicle.location.global_frame.alt)
return(39.668756, -127.334674, 10)
# Define the geotag function
async def geotag(temp_file, gps_data):
# gps_data should be a tuple containing latitude, longitude, and altitude
latitude, longitude, altitude = gps_data
# Construct the ExifTool command
exiftool_cmd = ['exiftool', '-GPSLatitude={}'.format(latitude), '-GPSLongitude={}'.format(longitude), '-GPSAltitude={}'.format(altitude), temp_file]
# Run the ExifTool command using subprocess
try:
subprocess.run(exiftool_cmd, check=True)
except subprocess.CalledProcessError as e:
print("Error geotagging photo: ", e)
return False
return True
# Define the main function
async def main():
while True:
# Wait for 5 seconds
# Capture photo and get GPS data asynchronously
temp_file_task = asyncio.create_task(capture_photo())
gps_data_task = asyncio.create_task(get_gps_data())
# Wait for both tasks to complete
temp_file = await temp_file_task
gps_data = await gps_data_task
# Geotag the image asynchronously
await geotag(temp_file, gps_data)
# Run the main function
asyncio.run(main())
In async def get_gps_data(): function you can use (I had used hard coded random value for testing)
You also you need to move geotagged image f(temp_file) to Target location of your choice…
You can add below code in async def geotag(temp_file, gps_data): function (inside try block)
Hello, All. I’m quite new to the DIY drones community and programing. I want to build a drone with a Pixhawk orange cube with Copter 4.5.1 and a computer companion Raspberry Pi 4 with its own camera module V2.
Objective:
To trigger the camera on my command from Mission Planner and Geotag the picture with the data from the Pixhawk’s GPS. I have successfully made the serial connection between the Pixhawk and Raspberry Pi. I have employed a relay module that will act as a button to trigger the RPi camera from the GPIO pin with a signal from the autopilot.
I saw this solution and I tried to add lines of code to obtain the desired result.
The main question is if the code below would work? If not could anybody point me in the right direction? Thank you all in advance for your attention!
import RPi.GPIO as GPIO
from picamera2 import Picamera2
import asyncio
import os
from datetime import datetime
import exifread
import dronekit
import time
import shutil
image_path=“/home/pi/my_captures/” #folder for iamges
camera configuration and initialization
camera = Picamera2()
camera_config = camera.create_still_configuration(main={“size”: (1920, 1080)}, lores={“size”: (640, 480)}, display=“lores”)
camera.configure(camera_config)
#Connect to the drone and wait for GPS fix
print(“Connecting to vehicle…”)
vehicle = dronekit.connect(‘/dev/ttyAMA0’, baud=57600)
print(“Waiting for GPS fix…”)
while not vehicle.gps_0.fix_type:
pass
print(“GPS fix obtained.”)
async def capture_photo(channel):
filename = datetime.now().strftime(“%Y%m%d_%H%M%S.jpg”)
temp_file = “/run/shm/{}”.format(filename) # use the ramdisk for faster I/O
camera.start_and_capture_file(temp_file)
return temp_file
Thank you for the replay. I will make the needed changes to the code and test it today. In the mean time I have a quick question about the exif data of the picture. How can I check on the Raspberry Pi if the GPS coord are saved in the correct way. So basically the question is how can I read the exif data after I finish the script?
I have see this solution ; pi@raspi /usr/freeware # time exiftool /snapshot.jpg
Hello and sorry for the late replay. I made the appropriate changes to the code and it works. Thank you for the solution and help. Now I have a follow up question to your code. Because I’m a beginner at programing , I’m a little confused with the temp_file created. I’m wondering if I could geotag the photos directly without the need of the temp_file being the intermediary, if so could you please provide an example.
Till now I’ve been working with the simple def function() and in your code I se you used asycn def function() . The question is ,if I modify your code and make all the function simple and then call them when I need them, will this ruin it?
Hi,
I’m happy to see that solution worked for you.
temp_file (image ) is stored in ram for faster read/write (exift data). you can store it in regular Sd card space but read/write operation will be slower (not ideal for geotagging ).
To do so, just replace the file path (/runn/shm/) to your SD cad path where you want to store it. temp_file = "/run/shm/{}".format(filename) # Use the ramdisk for faster I/O
Simple def function should be okay, but for time critical opration such as geotagging I have used async to capture the image and geotag at the same time. (capturing the photo and getting geolocation is done at the same time using async)
I’ve used your code and adapted it for my own use on RPI5 and using Arducam IMX519
It triggers the image capture off GPIO 16 and GND as a relay “button”
Here it is, still WIP but it’s working with GPS tagged to metadata, main change is that I’m using GPIOzero instead of RPI.GPIO. I don’t think that works on Raspberry Pi 5 at this stage
from gpiozero import Button
from picamera2 import Picamera2
import asyncio
import os
from datetime import datetime
import exifread
import dronekit
import shutil
import subprocess
# Update image storage location
image_path = "/home/PEPPIE/Desktop/ObiCam Images/"
# Camera configuration and initialization
camera = Picamera2()
camera_config = camera.create_still_configuration(
main={"size": (1920, 1080)}, lores={"size": (640, 480)}, display="lores"
)
camera.configure(camera_config)
# GPIO pin setup with GPIOZero
button = Button(16) # Change 16 to your actual GPIO pin
# Connect to the drone and wait for GPS fix
print("Connecting to vehicle...")
vehicle = dronekit.connect("/dev/ttyAMA0", baud=57600)
print("Waiting for GPS fix...")
while not vehicle.gps_0.fix_type:
pass
print("GPS fix obtained.")
async def capture_photo():
filename = datetime.now().strftime("%Y%m%d_%H%M%S.jpg")
temp_file = f"/run/shm/{filename}" # Use the ramdisk for faster I/O
camera.start_and_capture_file(temp_file)
# Move the image from temporary location to final destination
final_path = os.path.join(image_path, filename)
shutil.move(temp_file, final_path)
return final_path
async def get_gps_data():
return (
vehicle.location.global_frame.lat,
vehicle.location.global_frame.lon,
vehicle.location.global_frame.alt,
)
async def geotag(temp_file, gps_data):
latitude, longitude, altitude = gps_data
exiftool_cmd = [
"exiftool",
"-GPSLatitude={}".format(latitude),
"-GPSLongitude={}".format(longitude),
"-GPSAltitude={}".format(altitude),
temp_file,
]
try:
subprocess.run(exiftool_cmd, check=True)
except subprocess.CalledProcessError as e:
print("Error geotagging photo: ", e)
return False
return True
async def main():
while True:
# Wait for button press using GPIOZero
button.wait_for_press()
temp_file_task = asyncio.create_task(capture_photo())
gps_data_task = asyncio.create_task(get_gps_data())
temp_file = await temp_file_task
gps_data = await gps_data_task
await geotag(temp_file, gps_data)
# Execute the whole code
try:
asyncio.run(main())
except KeyboardInterrupt:
GPIOZero.cleanup()