Gli enti normativi governativi implementano diversi requisiti per garantire che la visibilità posteriore indiretta fornisca informazioni sufficienti per manovrare il veicolo in modo preciso e tempestivo. Ciò influisce sulla consapevolezza del conducente dell'ambiente circostante.
Per i sistemi di visibilità posteriore basati sul sistema di monitoraggio della videocamera (CMS), la National Highway Traffic Safety Administration (NHTSA) richiede di soddisfare questi requisiti (S6.6.2.3 di cui si fa riferimento in UNECE46):
S5.5.3 Tempo di risposta. L'immagine dello specchietto retrovisore che soddisfa i requisiti di S5.5.1 (Campo visivo) e S5.5.2 (Dimensioni), se testata in conformità con S14.2, viene visualizzata entro 2,0 secondi dall'inizio di un evento di retromarcia.
S5.5.4 Tempo di permanenza. L'immagine dello specchietto retrovisore che soddisfa i requisiti di S5.5.1 e S5.5.2 non viene visualizzata dopo la fine dell'evento di retromarcia.
S5.5.5 Disattivazione. L'immagine dello specchietto retrovisore che soddisfa i requisiti di S5.5.1 e S5.5.2 rimane visibile durante l'evento di retromarcia finché il conducente non modifica la visualizzazione o il selettore della direzione del veicolo non si sposta dalla posizione di retromarcia.
S6.6.2.3.3.5 Artefatti. Il manuale dell'operatore deve fare riferimento ai possibili artefatti e al loro impatto sull'occlusione parziale del campo visivo e degli oggetti, che potrebbe richiedere al conducente di essere particolarmente vigile e attento.
S6.2.2.3.4.1 Frequenza fotogrammi. I movimenti degli oggetti davanti alla videocamera vengono riprodotti in modo fluido e uniforme. La frequenza fotogrammi minima del sistema è di almeno 30 Hz (equivalente a 30 fps). In condizioni di scarsa illuminazione o durante le manovre a bassa velocità, la frequenza fotogrammi minima del sistema è di almeno 15 Hz.
S6.2.2.3.4.2 Tempo di formazione dell'immagine. Il tempo di formazione dell'immagine del monitor è inferiore a 55 ms a una temperatura di 22 gradi Celsius ± 5 gradi Celsius.
S6.2.2.3.4.3 Latenza di sistema. Un sistema di monitoraggio della videocamera (CMS) ha una latenza sufficientemente breve per riprodurre lo scenario quasi contemporaneamente. La latenza è inferiore a 200 ms a una temperatura di 22 gradi Celsius ± 5 gradi Celsius.
Abbiamo introdotto il sistema di visualizzazione estesa (EVS) di Android Automotive OS (AAOS) Extended View System (EVS) per rispettare questi requisiti su AAOS bare metal. Abbiamo introdotto un servizio simile per la virtualizzazione sui dispositivi AAOS con il renderer ad alta affidabilità (HAR), che dimostra anche la conformità a questi requisiti.
Pipeline di anteprima della videocamera
Queste cinque fasi compongono la pipeline di anteprima della videocamera:
Figura 1. Fasi della pipeline di anteprima della videocamera.
Il blocco del servizio videocamera si riferisce alla piattaforma del servizio videocamera e al relativo livello di astrazione che consente alle app di accedere e utilizzare le videocamere disponibili. La funzione del servizio di visualizzazione visualizza i dati delle immagini per gli utenti. L'app implementa i percorsi utente target con il servizio videocamera e il servizio di visualizzazione.
Il percorso utente principale per la visibilità posteriore è il seguente:
Il conducente posiziona il selettore della direzione (la marcia) in retromarcia per attivare un evento di retromarcia.
Il sistema trasmette l'evento di retromarcia. L'app riceve la trasmissione e inizializza il blocco di input della videocamera (servizio videocamera) e il renderer (servizio di visualizzazione).
Il blocco di input della videocamera inizializza la piattaforma del servizio videocamera e restituisce l'handle del servizio all'app.
Il renderer inizializza la finestra di visualizzazione per l'input della videocamera dal passaggio 4.
L'app richiede al blocco di input della videocamera di iniziare a inviare buffer di frame ed eventi.
L'app mette in coda i buffer di frame consegnati tramite i callback (asincroni). I buffer di frame sono di proprietà del blocco di input della videocamera, quindi l'app non può modificarli.
L'app rimuove dalla coda un buffer di frame (se la coda non è vuota) e compone la visualizzazione dell'utente. Gli utenti possono creare una copia per modificare i contenuti.
L'app invia un buffer al renderer.
Il renderer disegna i contenuti di un buffer ricevuto sul display.
Se l'evento di retromarcia è ancora in corso, vai al passaggio 7. Al termine dell'evento di retromarcia, l'app richiede al blocco di input della videocamera di interrompere l'invio di buffer di frame ed eventi dopo aver nascosto la visualizzazione all'utente.
L'app chiude facoltativamente una videocamera e rilascia il renderer.
La Figura 1 illustra il flusso. Questa immagine utilizza elementi dell'API della libreria della videocamera QNX per utilizzare la piattaforma del servizio videocamera.
Figura 2. Percorso utente principale di HAR.
Il blocco di input della videocamera dichiara tre interfacce:
CameraManager, dichiara i metodi per gestire i dispositivi videocamera; ad esempio, l'app utilizza questa interfaccia per aprire (riservare) un dispositivo videocamera di destinazione.CameraDevicedichiara i metodi per controllare un dispositivo videocamera; ad esempio, avviare o interrompere uno stream di dati.CameraStreamListenerdichiara un singolo metodo per ricevere vari eventi da una videocamera di destinazione.
Design
Questa sezione descrive in dettaglio la progettazione del sistema.
Esperienza utente
Il conducente può visualizzare l'anteprima della videocamera posteriore sul display del quadro strumenti quando inserisce la retromarcia. Il display interrompe l'anteprima della videocamera quando il conducente disinserisce la retromarcia.
È possibile attivare altri percorsi utente. Ad esempio, il conducente può visualizzare l'anteprima dell'area non visibile negli specchietti quando l'indicatore di direzione è attivo.
Avvia l'anteprima della videocamera
Quando utilizza le videocamere, l'app enumera e valuta le videocamere disponibili per trovare la migliore per lo scopo previsto. Ad esempio, per la visibilità posteriore, l'app cerca la videocamera che mostra il lato posteriore del veicolo nell'elenco delle videocamere disponibili.
L'app valuta questa caratteristica esaminando le caratteristiche di ogni videocamera, ad esempio posizione, direzione dell'obiettivo, frequenza fotogrammi, risoluzione di output e formato di output. Se più videocamere hanno le stesse caratteristiche richieste, l'app potrebbe esaminare caratteristiche aggiuntive, come il campo visivo e la distanza focale.
Questa immagine mostra una sequenza per avviare un'anteprima della videocamera con una configurazione statica della videocamera:
Figura 3. Avvia l'anteprima della videocamera con una configurazione statica della videocamera.
Interrompi l'anteprima della videocamera
L'app smette di fornire la visibilità posteriore al termine dell'evento di retromarcia. Per evitare di mostrare una schermata vuota o un'immagine statica, l'app nasconde prima la visualizzazione all'utente e poi richiede al blocco di input della videocamera di interrompere l'invio di eventi.
Questa immagine mostra una sequenza per interrompere uno stream di dati da un dispositivo videocamera di destinazione:
Figura 4. Interrompi lo stream di dati dal dispositivo videocamera di destinazione.
Errori
Un dispositivo videocamera può interrompere in modo imprevisto l'invio di un nuovo buffer di frame. Per rilevare questi incidenti, il blocco di input della videocamera potrebbe implementare un timer che scade all'arrivo di un nuovo frame e inviare una notifica alla scadenza del timer.
Quando l'app riceve una notifica, informa l'utente che l'anteprima della videocamera non è più in diretta e tenta di ripristinare un'anteprima della videocamera chiudendo un dispositivo videocamera e riaprendolo. La Figura 5 mostra come l'app gestisce un timeout:
Figura 5. Gestione di un timeout (stream di dati bloccato).
Il blocco di input della videocamera può segnalare incidenti diversi da uno stream di dati bloccato e incorporare ulteriori dettagli nei buffer. Gli OEM possono utilizzare questi metadati degli eventi per gestire gli incidenti sulla propria piattaforma.
Attività
L'API viene utilizzata dalle app in esecuzione sull'host e gestisce il display del quadro strumenti tramite HAR (blocchi blu nel diagramma riportato di seguito).
La Figura 5 illustra un diagramma di sistema:
Figura 6. Diagramma di sistema.
Servizi
È previsto che le chiamate API vengano eseguite nel contesto del processo di chiamata.
API
La nuova API è destinata solo alle app che gestiscono le anteprime della videocamera sul display del quadro strumenti tramite HAR. L'API è disponibile tramite il livello di astrazione della piattaforma e si collega dinamicamente.
L'interfaccia CameraInputBlock dichiara i metodi per inizializzare la funzionalità della videocamera e ottenere il gestore del blocco di input. L'app utilizza un'istanza CameraManager restituita per gestire i dispositivi videocamera.
// This class represents a camera input block for the application that manages the
// instrument cluster display with Harry.
public class CameraInputBlock : public InputBlock {
public:
// Clean up the resources.
virtual ~CameraInputBlock();
// A method inherited from InputBlock class. This method initializes
// CameraInputBlock instance; e.g. checking the platform camera service
// is live.
//
// @return CAMERA_EPERM if the platform camera service is not
// available.
// CAMERA_OK otherwise.
virtual CameraError init() override;
// A method inherited from InputBlock class. This method release all
// resources held by this CameraInputBlock instance.
virtual void release() override;
// This method returns a CameraManager instance. The caller uses
// this instance to manage camera devices.
//
// @param out If this method is successful, this points to a valid
// CameraManager instance.
// @return CAMERA_EACCESS when we fail to create CameraManager instance
// to return.
// CAMERA_OK otherwise.
virtual CameraError getCameraManager(
std::shared_ptr<CameraManager>* out) = 0;
private:
// Handle to manage camera devices.
std::shared_ptr<CameraManager> mMgr;
// Handle to manage camera devices that have been opened by clients.
std::set<CameraDevice> mCameras;
};
La classe CameraManager dichiara i metodi per aprire (o possedere) le videocamere e rilasciarle quando l'app ha terminato di utilizzarle. L'app può aprire più di una videocamera e utilizzare i relativi stream per creare un'esperienza con un campo visivo più ampio o con più visualizzazioni.
// This pure virtual class declares methods to manage camera devices.
public class CameraManager {
public:
// This method returns a list of CameraDescriptor objects representing
// available cameras.
//
// @param out A list of CameraDescriptor instances. This list may be
// empty if the platform camera service does not list any
// camera.
// @return CAMERA_EACCESS if we failed to build a camera list.
// CAMERA_OK otherwise.
virtual CameraError getCameraList(
std::vector<CameraDescriptor>* out) = 0;
// Open a camera device associated with a given string identifier.
//
// @param ID A string identifier of a camera device to request.
// @param out A pointer to CameraDevice shared pointer object. This
// is null when we fail to open a target device.
// @return CAMERA_ENODEV if no camera is associated with a given id.
// CAMERA_EACCESS if it fails to open a target device.
// CAMERA_OK otherwise.
virtual CameraError open(
std::string ID, std::shared_ptr<CameraDevice>* out) = 0;
// Close a camera device associated with a given string identifier.
// This method is assumed to be always successful.
//
// @param id A string identifier of a camera device to close.
virtual void close(std::string id) = 0;
};
Se le app non riescono a rilevare le videocamere da utilizzare, possono scegliere la videocamera che funziona meglio nel contesto. CameraManager::getCameraList() restituisce un elenco di istanze CameraDescriptor, che fornisce le caratteristiche di ogni videocamera.
La classe CameraDevice rappresenta un singolo dispositivo videocamera e dichiara i metodi per avviare e interrompere il relativo stream di dati. Se le caratteristiche della videocamera non sono note staticamente, i client le ottengono dal relativo descrittore e le analizzano.
Ad esempio, un client può ottenere un elenco di configurazioni di stream offerte da un dispositivo videocamera di destinazione dai relativi metadati e scegliere quella con gli attributi migliori (ad esempio, frequenze fotogrammi, risoluzioni e formato di output).
// This class represents a single camera device.
public class CameraDevice {
public:
// Start a data stream that attributes are matching to given
// configuration best.
// If a selected configuration is not given (null), a data stream is
// initiated in its default configuration and return.
//
// @param configuration Selected attributes of the imagery data stream.
// @param listener An object to listen to an active data stream.
// @param effective Actual attributes of started data stream.
// @return CAMERA_EINVAL if a listener object is invalid.
// CAMERA_EIO if we failed to start a video stream.
// CAMERA_OK otherwise.
virtual CameraError start(
std::shared_ptr<CameraStreamConfiguration>& configuration,
std::shared_ptr<CameraStreamListener>& listener,
std::shared_ptr<CameraStreamConfiguration>* effective) = 0;
// Stop a data stream.
virtual void stop() = 0;
// Get a camera descriptor.
//
// @param desc A set of attributes that defines this camera device.
// @return CAMERA_ENODATA if a descriptor is not available.
// CAMERA_OK otherwise.
CameraError getDescriptor(std::shared_ptr<CameraDescriptor>* desc) = 0;
// Return a consumed buffer to the camera device. A client of active
// stream must return a frame buffer explicitly by calling this method.
virtual void doneWithFrame(std::shared_ptr<FrameBuffer>& buffer) = 0;
private:
// Describe this camera device.
CameraDescriptor mDescriptor;
// A weak reference to a listening client.
std::weak_ptr<CameraStreamListener> mClient;
};
// This class declares attributes that characterize a camera device.
public class CameraDescriptor {
public:
// Unique std::string object to identify a single camera device.
std::string mId;
// A set of stream configurations this camera device is capable of. A
// camera must have at least one stream configuration.
std::set<CameraStreamConfiguration> mConfigurations;
// Are more attributes needed to exist, such as locations, lens
// facing directions, and intrinsic/extrinsic parameters?
};
// This class declares attributes that characterize an imagery data stream.
public class CameraStreamConfiguration {
public:
// Width of output of this stream in pixels.
unsigned int mWidthInPixels;
// Height of output of this stream in pixels.
unsigned int mHeightInPixels;
// An average number of frames per second.
double mFrameRate;
// A format of this stream's output. A client could calculate a
// byte-per-pixel (bpp) from this.
CameraColorFormat mFormat;
};
// This class represents a listener/callback object to listen to frames and
// events.
public class CameraStreamListener {
public:
// A listener method to receive various stream events including a new
// frame buffer.
//
// @param event CameraStreamEvent object that represents a single event
// such as an arrival of a new frame buffer, camera stream
// is terminated, and so forth.
virtual void onEvent(std::shared_ptr<CameraStreamEvent>* event) = 0;
};
CameraDevice::start() accetta tre argomenti:
Configurazione dello stream scelta dal chiamante.
Listener per ricevere gli eventi dello stream.
Puntatore a una configurazione dello stream efficace. Ti consigliamo vivamente di esaminare questo valore per gestire i buffer di frame in arrivo come previsto.
Quando CameraDevice::start() avvia uno stream di dati con la piattaforma del servizio videocamera, mantiene un riferimento debole all'oggetto listener del chiamante per rilevare la terminazione imprevista del chiamante.
Quando un client termina di utilizzare un buffer di frame, deve notificare a un dispositivo videocamera che non ha più bisogno del buffer di frame chiamando il metodo CameraDevice::doneWithFrame().
Quando uno stream viene avviato, un client riceve messaggi di eventi. Un messaggio comune è un nuovo buffer di frame. Tramite una funzione di callback registrata, un client riceve un evento kNewFrameBuffer che contiene i dati delle immagini insieme ai metadati del buffer di frame. StreamEventType dichiara altri tipi per gestire altri eventi dello stream. Ad esempio, stream di dati interrotto o bloccato.
// This class lists events possibly occurring while a data stream is active.
enum class CameraStreamEventType {
// A delivery of a new frame buffer.
kNewFrameBuffer,
// A data stream has been stopped.
kStreamStopped,
// No new frame buffer arrives for a while.
kStreamHang,
// Add more.
...
};
// This class represents a single instance of StreamEventType.
public class CameraStreamEvent {
public:
// Return a type of this event.
//
// @return CameraStreamEventType enum value.
CameraStreamEventType getType() { return mType; }
// Return a pointer to data associated with this event.
//
// @return A shared pointer object of the buffer that contains data for
// this event.
std::shared_ptr<void> getData() { return mData; }
private:
// Describe a type of this event.
CameraStreamEventType mType;
// A pointer to the data buffer.
std::shared_ptr<void> mData;
};
// This class inherits StreamEvent class and has additional fields to represent
// the frame buffer.
public class FrameBufferEvent : public CameraStreamEvent {
public:
// Return an identifier of this frame buffer.
//
// @return A unique integer value to identify this frame buffer.
int getBufferID() { return mBufferID; }
// Give access to frame buffer metadata.
//
// @return A shared pointer to the buffer that contains data besides
// the imagery data.
std::shared_ptr<void> getMetadata() { return mMetadata; }
private:
// Unique integer to identify this buffer.
int mBufferID;
// A pointer to metadata of this frame buffer.
std::shared_ptr<void> mMetadata;
};
Questo esempio mostra un'implementazione dell'interfaccia CameraInputBlock e della relativa app:
CameraError getCameraManager(std::shared_ptr<CameraManager>* out) {
// During an instantiation, CameraManager will retrieve a list of camera
// devices from the platform camera service and identify their attributes.
*out = std::make_shared<CameraManager>();
return CAMERA_OK;
}
// This method returns a list of CameraDescriptor objects representing available
// cameras.
CameraError CameraManager::getCameraList(std::vector<CameraDescriptor>* out) {
if (mCameraList.size() < 1) {
// Query a list of cameras and get their attributes.
}
*out = mCameraList;
return CAMERA_OK;
}
// Open a camera device associated with a given string identifier.
CameraError CameraManager::open(std::string id, std::shared_ptr<CameraDevice>* out) {
if (!mCameraList.contains(id)) {
// We cannot identify any camera with a given value.
return CAMERA_NODEV;
}
// During a construction, CameraDevice will obtain a handle of a target
// camera device from the platform camera service.
std::shared_ptr<CameraDevice> h = std::make_shared<CameraDevice>(id);
if (!h) {
// We fail to open a camera device.
return CAMERA_EACCESS;
}
*out = h;
return CAMERA_OK;
}
// Close a camera device associated with a given string identifier. This method
// is assumed to be always successful.
void CameraManager::close(std::string id) {
if (!mCameraList.contains(id)) {
// We ignore calls with unknown identifiers.
return;
}
// mCameraList.remove() returns an object removed from the list.
std::shared_ptr<CameraDevice> device = mCameraList.remove(id);
// Ensure a device stops streaming.
device->stop();
}
// Start a data stream that attributes are matching to given configuration
// best.
// If a selected configuration is not given (null), a data stream will be
// initiated in its default configuration and return.
CameraError CameraDevice::start(
std::shared_ptr<CameraStreamConfiguration>& configuration,
std::shared_ptr<CameraStreamListener>& listener,
std::shared_ptr<CameraStreamConfiguration>* effective) {
if (!listener) {
return CAMERA_EINVAL;
}
// selectStreamConfiguration examines this camera's stream configurations
// and returns the one closest to the selected configuration.
CameraStreamConfiguration config = selectStreamConfiguration(configuration);
// mDevice refers to the camera handle for the platform camera service. We
// may need to translate CameraStreamConfiguration for the platform service.
mDevice->configure(
configuration.mWidth, configuration.mHeight, configuration.mFormat);
// Start a data stream with a callback object.
if (!mDevice->startStream(mCallback)) {
// We failed to start a data stream.
return CAMERA_EIO;
}
return CAMERA_OK;
}
// Stop a data stream.
void CameraDevice::stop() {
if (!mDevice) {
// Nothing to do if we don't have a valid camera handle for the
// platform camera service.
return;
}
mDevice->stopStream();
}
// Get a camera descriptor.
CameraError CameraDevice::getDescriptor(std::shared_ptr<CameraDescriptor>* desc) {
if (!mDescriptor) {
return CAMERA_ENODATA;
}
*desc = *mDescriptor;
return CAMERA_OK;
}
// Return a consumed buffer to the camera device. A client of active stream
// must return a frame buffer explicitly by calling this method.
void CameraDevice::doneWithFrame(std::shared_ptr<FrameBuffer>& buffer) {
if (!mBufferRecords.contains(buffer.getId())) {
// Ignore a call with unknown frame buffer.
return;
}
// Simply remove from the record.
(void)mBufferRecords.remove(buffer.getId());
}
// This method handles gear-shift events.
void Application::handleGearShift(GearSelection selection) {
switch (selection) {
case GEAR_SELECTION_REVERSE:
// Upon the reverse gear selection, we are going to start a video
// stream and show its preview on the instrument cluster display.
(void)startStream(mCameraInputBlock);
// FIXME: Exact method to control the camera preview window on the
// instrument display is to be determined.
show(mRearVisibilityWindow);
break;
default:
// Upon all other gear selection, we are going to stop a video
// stream (if it's running) and hide the preview.
stopStream(mCameraInputBlock);
// FIXME: Exact method to control the camera preview window on the
// instrument display is to be determined.
hide(mRearVisibilityWindow);
break;
}
}
bool Application::startStream(std::shared_ptr<CameraInputBlock> handle) {
return handle->start(std::bind(&Application::handleStreamCallback, this);
}
void Application::stopStream(std::shared_ptr<CameraInputBlock> handle) {
handle->stop();
}
// This method handles a stream callback.
void Application::handleStreamCallback(StreamEvent& event) {
switch (event.getType()) {
case StreamEventType::kNewFrameBuffer:
// Handle a new frame buffer. We may just enqueue it for the
// future or forward to CameraInputBlock client.
break;
case StreamEventType::kStreamStopped:
// Handle as an incident if this event is not expected.
break;
// More cases to be added.
}
}
void Application::handleNewFrameBuffer(StreamEvent& event) {
// Enqueue a new frame buffer for the further processing. A buffer
// must be returned explicitly by calling
// CameraDevice.doneWithFrame(FrameBuffer&) method.
}
void Application::handleStreamEvent(StreamEvent& event) {
// Handle a received stream event except a new frame buffer's
// arrival; e.g. a video stream is terminated unexpectedly.
}
Rendimento
La visibilità posteriore è conforme a queste normative governative.
| Valore | Regolamento |
|---|---|
| Tempo di risposta | CFR 571.111 S5.5.3 |
| Frequenza fotogrammi | UNECE R46 6.2.2.3.4 |
| Tempo di formazione dell'immagine | UNECE R46 6.2.2.3.4.2 |
| Latenza di sistema | UNECE R46 6.2.2.3.4.3 |
Privacy
Specifiche per la privacy:
L'API non richiede alle implementazioni di raccogliere, registrare o archiviare informazioni che consentono l'identificazione personale (PII). Tuttavia, poiché i dati delle immagini acquisite (o i metadati associati) potrebbero contenere PII, l'app che utilizza l'API deve ottenere il consenso esplicito dell'utente.
Gli utenti non possono controllare i dispositivi videocamera per visualizzare l'anteprima sul display del quadro strumenti perché le videocamere svolgono ruoli fondamentali per la sicurezza. Gli OEM ottengono il consenso dell'utente durante la configurazione o dal conducente.
Questa API non supporta i client videocamera in background. Pertanto, l'indicatore della privacy, che informa gli utenti che un dispositivo videocamera sta acquisendo dati, non è incluso nell'ambito.