Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit ca32041

Browse files
authoredJul 23, 2024··
Merge pull request #2043 from arduino/hannes7eicher/Giga-Camera
[MKC-1267, HWGG-355] Add Webserial to Giga Camera Guide
2 parents a0e26ae + ce99fc4 commit ca32041

File tree

4 files changed

+134
-168
lines changed

4 files changed

+134
-168
lines changed
 
Loading
Loading
Lines changed: 134 additions & 168 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
---
22
title: GIGA R1 Camera Guide
3-
description: Learn about the GIGA R1 WiFi's camera connector, and how to use existing examples.
4-
tags: [ArduCAM, Camera, Processing]
3+
description: Learn about the GIGA R1 WiFi's camera connector, and how to stream data through Web Serial.
4+
tags: [ArduCAM, Camera, Web Serial]
55
author: Karl Söderby
66
hardware:
77
- hardware/10.mega/boards/giga-r1-wifi
@@ -16,38 +16,38 @@ The GIGA R1 has a dedicated camera connector that allows certain camera modules
1616
In this guide, we will explore the following:
1717

1818
- Where the camera connector is located.
19-
- What cameras are compatible.
20-
- What library to use.
21-
- How to setup a camera stream to a processing application.
19+
- What cameras are compatible?
20+
- What library to use?
21+
- How to set up a camera stream to a browser using Web Serial.
2222

2323
## Hardware & Software Needed
2424

2525
To follow and use the examples provided in this guide, you will need an [Arduino GIGA R1 WiFi](/hardware/giga-r1-wifi)
2626

2727
You will also need the following software:
28+
2829
- [Arduino IDE](https://www.arduino.cc/en/software) (any version).
29-
- [Processing](https://processing.org/download) (for displaying camera feed).
30+
- [Web Serial Web Application](https://arduino.github.io/labs-pages/web-serial-camera/) (for displaying camera feed).
3031

3132
## Supported Cameras
3233

33-
The GIGA R1 currently supports the following cameras, via the [Camera](https://github.com/arduino/ArduinoCore-mbed/tree/master/libraries/Camera) library that is bundled with the [Arduino Mbed PS GIGA Board Package](https://github.com/arduino/ArduinoCore-mbed):
34+
The GIGA R1 currently supports the following cameras, via the [Camera](https://github.com/arduino/ArduinoCore-mbed/tree/master/libraries/Camera) library that is bundled with the [Arduino Mbed Core](https://github.com/arduino/ArduinoCore-mbed):
3435

3536
- **OV7670** and **OV7675**
3637
- **GC2145**
3738
- **Himax HM01B0**
38-
- **Himax HM0360**
3939

4040
## Camera Connector
4141

4242
![Camera Connector on GIGA R1](assets/camera-connector-pins.png)
4343

44-
The 20 pin camera connector onboard the GIGA R1 is designed to be directly compatible with some breakout boards from ArduCam.
44+
The 20 pin camera connector onboard the GIGA R1 is designed to be directly compatible with some breakout boards from ArduCam.
4545

4646
This allows you to simply connect the camera module directly to the board, without making any additional circuit.
4747

4848
![Camera Module Connected](assets/camera-connector-photo.png)
4949

50-
Some of the 20 pin connector breakout boards from ArduCam can be found [here](https://www.arducam.com/product-category/stm32-camera-modules-dcmi-and-spi/).
50+
Some of the 20 pin connector breakout boards from ArduCam can be found [here](https://www.arducam.com/product-category/embedded-camera-module/camera-breakout-board/).
5151

5252
The complete pin map can be found below:
5353

@@ -70,21 +70,33 @@ You can also view the schematic for this connector in more detail just below. Th
7070

7171
![Schematic for Camera Connector (J6).](assets/camera-schematic.png)
7272

73-
## Raw Bytes Over Serial (Processing)
74-
75-
![Live view of the camera.](assets/processing-example.png)
73+
## Raw Bytes Over Serial
7674

77-
This example allows you to stream the sensor data from your camera to a Processing application, using serial over USB. This will allow you to see the image directly in your computer.
78-
79-
***This example requires a version of [Processing](https://processing.org/download) on your machine.***
75+
This example allows you to stream the sensor data from your camera to a web interface, using serial over USB. This will allow you to see the image directly in your browser.
8076

8177
### Step 1: Arduino
8278

8379
Upload the following sketch to your board.
8480

85-
This sketch is also available in the Arduino IDE via **Examples > Camera > CameraCaptureRawBytes**.
81+
This sketch is also available in the Arduino IDE via **Examples > Camera > CameraCaptureWebSerial**.
8682

8783
```arduino
84+
/*
85+
* This example shows how to capture images from the camera and send them over Web Serial.
86+
*
87+
* There is a companion web app that receives the images and displays them in a canvas.
88+
* It can be found in the "extras" folder of this library.
89+
* The on-board LED lights up while the image is being sent over serial.
90+
*
91+
* Instructions:
92+
* 1. Make sure the correct camera is selected in the #include section below by uncommenting the correct line.
93+
* 2. Upload this sketch to your camera-equipped board.
94+
* 3. Open the web app in a browser (Chrome or Edge) by opening the index.html file
95+
* in the "WebSerialCamera" folder which is located in the "extras" folder.
96+
*
97+
* Initial author: Sebastian Romero @sebromero
98+
*/
99+
88100
#include "camera.h"
89101
90102
#ifdef ARDUINO_NICLA_VISION
@@ -93,14 +105,19 @@ This sketch is also available in the Arduino IDE via **Examples > Camera > Camer
93105
Camera cam(galaxyCore);
94106
#define IMAGE_MODE CAMERA_RGB565
95107
#elif defined(ARDUINO_PORTENTA_H7_M7)
108+
// uncomment the correct camera in use
96109
#include "hm0360.h"
97110
HM0360 himax;
111+
// #include "himax.h";
112+
// HM01B0 himax;
98113
Camera cam(himax);
99114
#define IMAGE_MODE CAMERA_GRAYSCALE
100115
#elif defined(ARDUINO_GIGA)
101-
#include "ov7670.h"
102-
OV7670 ov7670;
103-
Camera cam(ov7670);
116+
#include "ov767x.h"
117+
// uncomment the correct camera in use
118+
OV7670 ov767x;
119+
// OV7675 ov767x;
120+
Camera cam(ov767x);
104121
#define IMAGE_MODE CAMERA_RGB565
105122
#else
106123
#error "This board is unsupported."
@@ -110,188 +127,137 @@ This sketch is also available in the Arduino IDE via **Examples > Camera > Camer
110127
Other buffer instantiation options:
111128
FrameBuffer fb(0x30000000);
112129
FrameBuffer fb(320,240,2);
113-
*/
114-
FrameBuffer fb;
115130
116-
unsigned long lastUpdate = 0;
131+
If resolution higher than 320x240 is required, please use external RAM via
132+
#include "SDRAM.h"
133+
FrameBuffer fb(SDRAM_START_ADDRESS);
134+
...
135+
// and adding in setup()
136+
SDRAM.begin();
137+
*/
138+
constexpr uint16_t CHUNK_SIZE = 512; // Size of chunks in bytes
139+
constexpr uint8_t RESOLUTION = CAMERA_R320x240; // CAMERA_R160x120
140+
constexpr uint8_t CONFIG_SEND_REQUEST = 2;
141+
constexpr uint8_t IMAGE_SEND_REQUEST = 1;
117142
143+
uint8_t START_SEQUENCE[4] = { 0xfa, 0xce, 0xfe, 0xed };
144+
uint8_t STOP_SEQUENCE[4] = { 0xda, 0xbb, 0xad, 0x00 };
145+
FrameBuffer fb;
118146
119-
void blinkLED(uint32_t count = 0xFFFFFFFF)
120-
{
121-
pinMode(LED_BUILTIN, OUTPUT);
147+
/**
148+
* Blinks the LED a specified number of times.
149+
* @param ledPin The pin number of the LED.
150+
* @param count The number of times to blink the LED. Default is 0xFFFFFFFF.
151+
*/
152+
void blinkLED(int ledPin, uint32_t count = 0xFFFFFFFF) {
122153
while (count--) {
123-
digitalWrite(LED_BUILTIN, LOW); // turn the LED on (HIGH is the voltage level)
154+
digitalWrite(ledPin, LOW); // turn the LED on (HIGH is the voltage level)
124155
delay(50); // wait for a second
125-
digitalWrite(LED_BUILTIN, HIGH); // turn the LED off by making the voltage LOW
156+
digitalWrite(ledPin, HIGH); // turn the LED off by making the voltage LOW
126157
delay(50); // wait for a second
127158
}
128159
}
129160
130161
void setup() {
162+
pinMode(LED_BUILTIN, OUTPUT);
163+
pinMode(LEDR, OUTPUT);
164+
digitalWrite(LED_BUILTIN, HIGH);
165+
digitalWrite(LEDR, HIGH);
166+
131167
// Init the cam QVGA, 30FPS
132-
if (!cam.begin(CAMERA_R320x240, IMAGE_MODE, 30)) {
133-
blinkLED();
168+
if (!cam.begin(RESOLUTION, IMAGE_MODE, 30)) {
169+
blinkLED(LEDR);
134170
}
135171
136-
blinkLED(5);
172+
blinkLED(LED_BUILTIN, 5);
137173
}
138174
139-
void loop() {
140-
if(!Serial) {
141-
Serial.begin(921600);
142-
while(!Serial);
143-
}
144-
145-
// Time out after 2 seconds and send new data
146-
bool timeoutDetected = millis() - lastUpdate > 2000;
147-
148-
// Wait for sync byte.
149-
if(!timeoutDetected && Serial.read() != 1) return;
175+
/**
176+
* Sends a chunk of data over a serial connection.
177+
*
178+
* @param buffer The buffer containing the data to be sent.
179+
* @param bufferSize The size of the buffer.
180+
*/
181+
void sendChunk(uint8_t* buffer, size_t bufferSize){
182+
Serial.write(buffer, bufferSize);
183+
Serial.flush();
184+
delay(1); // Optional: Add a small delay to allow the receiver to process the chunk
185+
}
150186
151-
lastUpdate = millis();
152-
187+
/**
188+
* Sends a frame of camera image data over a serial connection.
189+
*/
190+
void sendFrame(){
153191
// Grab frame and write to serial
154-
if (cam.grabFrame(fb, 3000) == 0) {
155-
Serial.write(fb.getBuffer(), cam.frameSize());
192+
if (cam.grabFrame(fb, 3000) == 0) {
193+
byte* buffer = fb.getBuffer();
194+
size_t bufferSize = cam.frameSize();
195+
digitalWrite(LED_BUILTIN, LOW);
196+
197+
sendChunk(START_SEQUENCE, sizeof(START_SEQUENCE));
198+
199+
// Split buffer into chunks
200+
for(size_t i = 0; i < bufferSize; i += CHUNK_SIZE) {
201+
size_t chunkSize = min(bufferSize - i, CHUNK_SIZE);
202+
sendChunk(buffer + i, chunkSize);
203+
}
204+
205+
sendChunk(STOP_SEQUENCE, sizeof(STOP_SEQUENCE));
206+
207+
digitalWrite(LED_BUILTIN, HIGH);
156208
} else {
157209
blinkLED(20);
158210
}
159211
}
160212
161-
```
162-
163-
### Step 2: Processing
164-
165-
The following Processing sketch will launch a Java app that allows you to view the camera feed. As data is streamed via serial, make sure you close the Serial Monitor during this process, else it will not work.
166-
167-
***Important! Make sure to replace the following line in the code below: `/dev/cu.usbmodem14301`, with the name of your port.***
168-
169-
Click on the **"PLAY"** button to initialize the app.
170-
171-
```cpp
172-
/*
173-
Use with the Examples -> CameraCaptureRawBytes Arduino sketch.
174-
This example code is in the public domain.
175-
*/
176-
177-
import processing.serial.*;
178-
import java.nio.ByteBuffer;
179-
import java.nio.ByteOrder;
180-
181-
Serial myPort;
213+
/**
214+
* Sends the camera configuration over a serial connection.
215+
* This is used to configure the web app to display the image correctly.
216+
*/
217+
void sendCameraConfig(){
218+
Serial.write(IMAGE_MODE);
219+
Serial.write(RESOLUTION);
220+
Serial.flush();
221+
delay(1);
222+
}
182223
183-
// must match resolution used in the Arduino sketch
184-
final int cameraWidth = 320;
185-
final int cameraHeight = 240;
224+
void loop() {
225+
if(!Serial) {
226+
Serial.begin(115200);
227+
while(!Serial);
228+
}
186229
187-
// Must match the image mode in the Arduino sketch
188-
final boolean useGrayScale = true;
230+
if(!Serial.available()) return;
189231
190-
// Must match the baud rate in the Arduino sketch
191-
final int baudRate = 921600;
232+
byte request = Serial.read();
192233
193-
final int cameraBytesPerPixel = useGrayScale ? 1 : 2;
194-
final int cameraPixelCount = cameraWidth * cameraHeight;
195-
final int bytesPerFrame = cameraPixelCount * cameraBytesPerPixel;
196-
final int timeout = int((bytesPerFrame / float(baudRate / 10)) * 1000 * 2); // Twice the transfer rate
234+
switch(request){
235+
case IMAGE_SEND_REQUEST:
236+
sendFrame();
237+
break;
238+
case CONFIG_SEND_REQUEST:
239+
sendCameraConfig();
240+
break;
241+
}
242+
243+
}
197244
198-
PImage myImage;
199-
byte[] frameBuffer = new byte[bytesPerFrame];
200-
int lastUpdate = 0;
201-
boolean shouldRedraw = false;
245+
```
202246

203-
void setup() {
204-
size(640, 480);
247+
### Step 2: Web Serial
205248

206-
// If you have only ONE serial port active you may use this:
207-
//myPort = new Serial(this, Serial.list()[0], baudRate); // if you have only ONE serial port active
249+
Open the [Web Serial Interface](https://arduino.github.io/labs-pages/web-serial-camera/) which allows you to view the camera feed. Make sure to close the Serial Monitor in the Arduino IDE beforehand, otherwise it will not work as the serial port would be occupied.
208250

209-
// If you know the serial port name
210-
//myPort = new Serial(this, "COM5", baudRate); // Windows
211-
//myPort = new Serial(this, "/dev/ttyACM0", baudRate); // Linux
212-
myPort = new Serial(this, "/dev/cu.usbmodem14301", baudRate); // Mac
251+
Press on **Connect** and select the correct port.
213252

214-
// wait for a full frame of bytes
215-
myPort.buffer(bytesPerFrame);
253+
![Select Port](./assets/connect_port.png)
216254

217-
myImage = createImage(cameraWidth, cameraHeight, ALPHA);
218-
219-
// Let the Arduino sketch know we're ready to receive data
220-
myPort.write(1);
221-
}
255+
You should now be able to see the camera feed.
222256

223-
void draw() {
224-
// Time out after a few seconds and ask for new data
225-
if(millis() - lastUpdate > timeout) {
226-
println("Connection timed out.");
227-
myPort.clear();
228-
myPort.write(1);
229-
}
230-
231-
if(shouldRedraw){
232-
PImage img = myImage.copy();
233-
img.resize(640, 480);
234-
image(img, 0, 0);
235-
shouldRedraw = false;
236-
}
237-
}
238-
239-
int[] convertRGB565ToRGB888(short pixelValue){
240-
//RGB565
241-
int r = (pixelValue >> (6+5)) & 0x01F;
242-
int g = (pixelValue >> 5) & 0x03F;
243-
int b = (pixelValue) & 0x01F;
244-
//RGB888 - amplify
245-
r <<= 3;
246-
g <<= 2;
247-
b <<= 3;
248-
return new int[]{r,g,b};
249-
}
250-
251-
void serialEvent(Serial myPort) {
252-
lastUpdate = millis();
253-
254-
// read the received bytes
255-
myPort.readBytes(frameBuffer);
256-
257-
// Access raw bytes via byte buffer
258-
ByteBuffer bb = ByteBuffer.wrap(frameBuffer);
259-
260-
// Ensure proper endianness of the data for > 8 bit values.
261-
// The 1 byte bb.get() function will always return the bytes in the correct order.
262-
bb.order(ByteOrder.BIG_ENDIAN);
263-
264-
int i = 0;
265-
266-
while (bb.hasRemaining()) {
267-
if(useGrayScale){
268-
// read 8-bit pixel data
269-
byte pixelValue = bb.get();
270-
271-
// set pixel color
272-
myImage.pixels[i++] = color(Byte.toUnsignedInt(pixelValue));
273-
} else {
274-
// read 16-bit pixel data
275-
int[] rgbValues = convertRGB565ToRGB888(bb.getShort());
276-
277-
// set pixel RGB color
278-
myImage.pixels[i++] = color(rgbValues[0], rgbValues[1], rgbValues[2]);
279-
}
280-
}
281-
282-
myImage.updatePixels();
283-
284-
// Ensures that the new image data is drawn in the next draw loop
285-
shouldRedraw = true;
286-
287-
// Let the Arduino sketch know we received all pixels
288-
// and are ready for the next frame
289-
myPort.write(1);
290-
}
291-
```
257+
There is also a variety of video filters that can be applied.
292258

293-
If all goes well, you should now be able to see the camera feed.
259+
![Video Filters](./assets/video_filter.png)
294260

295261
## Summary
296262

297-
In this article, we learned a bit more about the camera connector on board the GIGA R1 board, how it is connected to the STM32H747XI microcontroller, and a simple example on how to connect an inexpensive OV7675 camera module to a Processing application.
263+
In this article, we learned a bit more about the camera connector on board the GIGA R1 board, how it is connected to the STM32H747XI microcontroller, and a simple example of how to connect ArduCam camera modules through web serial.

0 commit comments

Comments
 (0)
Please sign in to comment.