Warm-up

Allowing the Zivid 3D camera to warm up and reach thermal equilibrium can improve the overall accuracy and success of an application. In this article, we explain why and how to warm up the Zivid 3D camera.

Tip

As of SDK v2.7.0 a Thermal Stabilization mode is available. With this mode enabled the warm-up period is reduced.

Why warm-up is needed

Zivid 3D cameras have active electronic components (e.g. white light projector) that produce heat when being used. The internal heat-up causes components to undergo mechanical variations when their body temperature changes.

These mechanical changes cause tiny displacements in essential optical components which affects the triangulation accuracy when calculating the position of the points in the point cloud. The 3D calibration of the camera is less accurate during a warming or cooling phase because of the many unknown possible temperature states each internal component can be in. We call this phenomenon warm-up drift.

It is recommended to control the camera temperature and allow enough time for all components to reach a steady temperature (thermal equilibrium). Consequently, Zivid 3D calibration can recognize and accurately predict the physical state of the camera and produce a correct point cloud.

Temperature change - camera vs. environment

Warm-up tests show that the internal temperature of the Zivid 3D camera can temporarily change up to 1.5 °C/min (15 °C in 10 minutes) at the fastest possible capture cycle (live mode). For a more typical capture cycle, e.g. capturing every 5 seconds, the internal temperature change is two to three times slower (0.5 - 1 °C/min).

On the other hand, the daily air temperature changes up to 0.03 °C/min (e.g. 10 °C in 6 hours). This is two orders of magnitude slower than the temporary temperature change in the camera during warm-up.

Zivid 3D cameras have a floating calibration that can compensate for ambient temperature change, thus ensuring stability in the recommended temperature range. Cameras that are warmed up and used properly exhibit a stable performance throughout the entire specified ambient temperature range.

Warmup

When to perform warm-up

It is recommended to warm up the camera in the following conditions:

  • The application requires tight tolerances, for example:

    • Picking applications with < 5 mm per meter distance from the camera.

    • Inspection applications with < 0.5% trueness error requirements.

  • The application requires moderate capture cycles (faster than once every 10 seconds).

  • Before infield correction.

  • Before hand-eye calibration.

  • Before running production.

  • When the camera has not been connected to power e.g. after mechanically installing the camera.

  • When the camera has been powered on but has not been capturing point clouds in the last 20 minutes e.g. when starting a production cell in the morning.

How to perform warm-up

To warm up the camera, capture 3D point clouds for 10 minutes with a fixed capture cycle.

Connect

The first step is to connect to the camera.

Go to source

source

Zivid::Application zivid;

std::cout << "Connecting to camera" << std::endl;
auto camera = zivid.connectCamera();
Go to source

source

var zivid = new Zivid.NET.Application();

Console.WriteLine("Connecting to camera");
var camera = zivid.ConnectCamera();
Go to source

source

app = zivid.Application()

print("Connecting to camera")
camera = app.connect_camera()

Set Capture cycle and settings

During warm-up, the capture cycle should be as similar as possible to the capture cycle in the application (bin-picking, de-palletization, etc.).

If the deployed camera captures, e.g., once every 5 seconds, it should capture with the same interval during the warm-up phase. If the camera does not have a stable capture cycle, the capture cycle during the warm-up phase should be between the extreme values. For example, if it captures once in 5 to 11 seconds in the application, it should capture once in 8 seconds during warm-up. If the delay between the captures in the application is longer than 10 seconds, there is no need to warm up the camera.

Note

Thermal Stabilization mode should be enabled if the application capture cycle has a variable period.

The camera settings used during the warm-up should also be as similar as possible to those in the application (pre-configured, loaded from YML file or capture assistant).

Go to source

source

const auto warmupTime = std::chrono::minutes(10);
const auto captureCycle = std::chrono::seconds{ captureCycleSeconds };
const auto settings = loadOrSuggestSettings(camera, settingsPath);
Go to source

source

var warmupTime = TimeSpan.FromMinutes(10);
var captureCycle = opts.CaptureCycle.HasValue ? TimeSpan.FromSeconds(opts.CaptureCycle.Value) : TimeSpan.FromSeconds(5);
var settings = LoadOrSuggestSettings(camera, opts.SettingsPath);
Go to source

source

warmup_time = timedelta(minutes=10)
capture_cycle = timedelta(seconds=user_options.capture_cycle)
settings = _load_or_suggest_settings(camera, user_options.settings_path)

Load or suggest settings

Go to source

source

Zivid::Settings loadOrSuggestSettings(Zivid::Camera &camera, const std::string &settingsPath)
{
    if(!settingsPath.empty())
    {
        std::cout << "Loading settings from file" << std::endl;
        return Zivid::Settings(settingsPath);
    }
    std::cout << "Getting camera settings from capture assistant" << std::endl;
    const auto maxCaptureTime = std::chrono::milliseconds(1000);
    const auto parameters = Zivid::CaptureAssistant::SuggestSettingsParameters{
        Zivid::CaptureAssistant::SuggestSettingsParameters::AmbientLightFrequency::none,
        Zivid::CaptureAssistant::SuggestSettingsParameters::MaxCaptureTime{ maxCaptureTime }
    };
    return Zivid::CaptureAssistant::suggestSettings(camera, parameters);
Go to source

source

static Zivid.NET.Settings LoadOrSuggestSettings(Zivid.NET.Camera camera, string settingsPath)
{
    if (settingsPath != null)
    {
        Console.WriteLine("Loading settings from file");
        return new Zivid.NET.Settings(settingsPath);
    }
    Console.WriteLine("Getting camera settings from capture assistant");
    var suggestSettingsParameters = new Zivid.NET.CaptureAssistant.SuggestSettingsParameters
    {
        MaxCaptureTime = Duration.FromMilliseconds(1000),
        AmbientLightFrequency =
            Zivid.NET.CaptureAssistant.SuggestSettingsParameters.AmbientLightFrequencyOption.none
    };
    return Zivid.NET.CaptureAssistant.Assistant.SuggestSettings(camera, suggestSettingsParameters);
}
Go to source

source

def _load_or_suggest_settings(camera: zivid.Camera, settings_path: str) -> zivid.Settings:
    """Load settings from YML file or find them with the assisted capture

    Args:
        camera: Zivid camera
        settings_path: Path to the YML file that contains camera settings

    Returns:
        Camera Settings

    """

    if settings_path:
        print("Loading settings from file")
        return zivid.Settings.load(Path(settings_path))
    print("Getting camera settings from capture assistant")
    suggest_settings_parameters = zivid.capture_assistant.SuggestSettingsParameters(
        max_capture_time=timedelta(milliseconds=1000),
        ambient_light_frequency=zivid.capture_assistant.SuggestSettingsParameters.AmbientLightFrequency.none,
    )
    return zivid.capture_assistant.suggest_settings(camera, suggest_settings_parameters)

Note

This warm-up method uses the white light projector as a heating element to warm up the camera during a steady capture cycle. The ratio of time the projector is turned on compared to the total cycle time is called the duty cycle. The duty cycle affects the rate at which the camera heats up as well as the final, steady-state temperature of the camera after the warm-up phase.

Warm up the camera

To warm up the camera, capture 3D point clouds in a loop for 10 minutes until the temperature stabilizes.

Go to source

source

std::cout << "Starting warm up for: " << warmupTime.count() << " minutes" << std::endl;

const auto beforeWarmup = SteadyClock::now();

while(SteadyClock::now() - beforeWarmup < warmupTime)
{
    const auto beforeCapture = SteadyClock::now();
    camera.capture(settings);
    const auto afterCapture = SteadyClock::now();
    const auto captureTime = afterCapture - beforeCapture;
    if(captureTime < captureCycle)
    {
        std::this_thread::sleep_for(captureCycle - captureTime);
    }
    else
    {
        std::cout << "Your capture time is longer than your desired capture cycle."
                  << "Please increase the desired capture cycle." << std::endl;
    }

    const auto remainingTime = warmupTime - (SteadyClock::now() - beforeWarmup);

    const auto remainingTimeMinutes = std::chrono::duration_cast<std::chrono::minutes>(remainingTime);
    const auto remainingTimeSeconds =
        std::chrono::duration_cast<std::chrono::seconds>(remainingTime - remainingTimeMinutes);
    std::cout << "Remaining time: " << remainingTimeMinutes.count() << " minutes, "
              << remainingTimeSeconds.count() << " seconds." << std::endl;
}
std::cout << "Warm up completed" << std::endl;
Go to source

source

DateTime beforeWarmup = DateTime.Now;

Console.WriteLine("Starting warm up for: {0} minutes", warmupTime.Minutes);

while (DateTime.Now.Subtract(beforeWarmup) < warmupTime)
{
    var beforeCapture = DateTime.Now;
    camera.Capture(settings);
    var afterCapture = DateTime.Now;

    var captureTime = afterCapture.Subtract(beforeCapture);

    if (captureTime < captureCycle)
    {
        Thread.Sleep(captureCycle.Subtract(captureTime));
    }
    else
    {
        Console.WriteLine(
            "Your capture time is longer than your desired capture cycle. Please increase the desired capture cycle.");
    }
    var remainingTime = warmupTime.Subtract(DateTime.Now.Subtract(beforeWarmup));
    var remainingMinutes = Math.Floor(remainingTime.TotalMinutes);
    var remainingSeconds = Math.Floor(remainingTime.TotalSeconds) % 60;

    Console.WriteLine("Remaining time: {0} minutes, {1} seconds.", remainingMinutes, remainingSeconds);
}

Console.WriteLine("Warm up completed");
Go to source

source

before_warmup = datetime.now()

print(f"Starting warm up for {warmup_time} minutes")
while (datetime.now() - before_warmup) < warmup_time:
    before_capture = datetime.now()
    camera.capture(settings)
    after_capture = datetime.now()

    duration = after_capture - before_capture

    if duration.seconds <= capture_cycle.seconds:
        sleep(capture_cycle.seconds - duration.seconds)
    else:
        print(
            "Your capture time is longer than your desired capture cycle. \
             Please increase the desired capture cycle."
        )

    remaining_time = warmup_time - (datetime.now() - before_warmup)
    remaining_time_minutes = remaining_time.seconds // 60
    remaining_time_seconds = remaining_time.seconds % 60
    print(f"Remaining time: {remaining_time_minutes} minutes, {remaining_time_seconds} seconds.")

print("Warm up completed")

For an implementation example, see the complete warm-up code sample below.

Go to source

source

/*
Short example of a basic way to warm up the camera with specified time and capture cycle.
*/

#include <Zivid/Zivid.h>

#include <clipp.h>

#include <chrono>
#include <iostream>
#include <thread>

using SteadyClock = std::chrono::steady_clock;
using Duration = std::chrono::nanoseconds;

namespace
{
    Zivid::Settings loadOrSuggestSettings(Zivid::Camera &camera, const std::string &settingsPath)
    {
        if(!settingsPath.empty())
        {
            std::cout << "Loading settings from file" << std::endl;
            return Zivid::Settings(settingsPath);
        }
        std::cout << "Getting camera settings from capture assistant" << std::endl;
        const auto maxCaptureTime = std::chrono::milliseconds(1000);
        const auto parameters = Zivid::CaptureAssistant::SuggestSettingsParameters{
            Zivid::CaptureAssistant::SuggestSettingsParameters::AmbientLightFrequency::none,
            Zivid::CaptureAssistant::SuggestSettingsParameters::MaxCaptureTime{ maxCaptureTime }
        };
        return Zivid::CaptureAssistant::suggestSettings(camera, parameters);
    }
} // namespace

int main(int argc, char **argv)
{
    try
    {
        std::string settingsPath;
        size_t captureCycleSeconds = 5;

        auto settingsOption = clipp::option("--settings-path")
                              & clipp::value("Path to the YML file that contains camera settings", settingsPath);
        auto captureCycleOption =
            clipp::option("--capture-cycle") & clipp::value("Capture cycle in seconds", captureCycleSeconds);

        auto cli = (settingsOption, captureCycleOption);

        if(!parse(argc, argv, cli))
        {
            auto fmt = clipp::doc_formatting{}.alternatives_min_split_size(1).surround_labels("\"", "\"");
            std::cout << clipp::usage_lines(cli, "Warmup", fmt) << std::endl;
            throw std::runtime_error{ "Invalid usage" };
        }
        Zivid::Application zivid;

        std::cout << "Connecting to camera" << std::endl;
        auto camera = zivid.connectCamera();
        const auto warmupTime = std::chrono::minutes(10);
        const auto captureCycle = std::chrono::seconds{ captureCycleSeconds };
        const auto settings = loadOrSuggestSettings(camera, settingsPath);

        std::cout << "Starting warm up for: " << warmupTime.count() << " minutes" << std::endl;

        const auto beforeWarmup = SteadyClock::now();

        while(SteadyClock::now() - beforeWarmup < warmupTime)
        {
            const auto beforeCapture = SteadyClock::now();
            camera.capture(settings);
            const auto afterCapture = SteadyClock::now();
            const auto captureTime = afterCapture - beforeCapture;
            if(captureTime < captureCycle)
            {
                std::this_thread::sleep_for(captureCycle - captureTime);
            }
            else
            {
                std::cout << "Your capture time is longer than your desired capture cycle."
                          << "Please increase the desired capture cycle." << std::endl;
            }

            const auto remainingTime = warmupTime - (SteadyClock::now() - beforeWarmup);

            const auto remainingTimeMinutes = std::chrono::duration_cast<std::chrono::minutes>(remainingTime);
            const auto remainingTimeSeconds =
                std::chrono::duration_cast<std::chrono::seconds>(remainingTime - remainingTimeMinutes);
            std::cout << "Remaining time: " << remainingTimeMinutes.count() << " minutes, "
                      << remainingTimeSeconds.count() << " seconds." << std::endl;
        }
        std::cout << "Warm up completed" << std::endl;
    }
    catch(const std::exception &e)
    {
        std::cerr << "Error: " << Zivid::toString(e) << std::endl;
        std::cout << "Press enter to exit." << std::endl;
        std::cin.get();
        return EXIT_FAILURE;
    }

    return EXIT_SUCCESS;
}
Go to source

source

/*
A basic warm-up method for a Zivid camera with specified time and capture cycle.
*/

using CommandLine;
using System;
using System.Runtime.InteropServices;
using System.Threading;
using Duration = Zivid.NET.Duration;

class Program
{
    public class Options
    {
        [Option('s', "settings-path", Required = false, HelpText = "Path to the YML file that contains camera settings.")]
        public string SettingsPath { get; set; }

        [Option('c', "capture-cycle", Required = false, HelpText = "Capture cycle in seconds.")]
        public int? CaptureCycle { get; set; }
    }

    static Zivid.NET.Settings LoadOrSuggestSettings(Zivid.NET.Camera camera, string settingsPath)
    {
        if (settingsPath != null)
        {
            Console.WriteLine("Loading settings from file");
            return new Zivid.NET.Settings(settingsPath);
        }
        Console.WriteLine("Getting camera settings from capture assistant");
        var suggestSettingsParameters = new Zivid.NET.CaptureAssistant.SuggestSettingsParameters
        {
            MaxCaptureTime = Duration.FromMilliseconds(1000),
            AmbientLightFrequency =
                Zivid.NET.CaptureAssistant.SuggestSettingsParameters.AmbientLightFrequencyOption.none
        };
        return Zivid.NET.CaptureAssistant.Assistant.SuggestSettings(camera, suggestSettingsParameters);
    }

    static int Main(string[] args)
    {
        return Parser.Default.ParseArguments<Options>(args)
        .MapResult(
            (Options opts) => RunWarmupWithOptionsAndReturnExitCode(opts),
            errs => 1);
    }

    static int RunWarmupWithOptionsAndReturnExitCode(Options opts)
    {
        try
        {
            var zivid = new Zivid.NET.Application();

            Console.WriteLine("Connecting to camera");
            var camera = zivid.ConnectCamera();
            var warmupTime = TimeSpan.FromMinutes(10);
            var captureCycle = opts.CaptureCycle.HasValue ? TimeSpan.FromSeconds(opts.CaptureCycle.Value) : TimeSpan.FromSeconds(5);
            var settings = LoadOrSuggestSettings(camera, opts.SettingsPath);

            DateTime beforeWarmup = DateTime.Now;

            Console.WriteLine("Starting warm up for: {0} minutes", warmupTime.Minutes);

            while (DateTime.Now.Subtract(beforeWarmup) < warmupTime)
            {
                var beforeCapture = DateTime.Now;
                camera.Capture(settings);
                var afterCapture = DateTime.Now;

                var captureTime = afterCapture.Subtract(beforeCapture);

                if (captureTime < captureCycle)
                {
                    Thread.Sleep(captureCycle.Subtract(captureTime));
                }
                else
                {
                    Console.WriteLine(
                        "Your capture time is longer than your desired capture cycle. Please increase the desired capture cycle.");
                }
                var remainingTime = warmupTime.Subtract(DateTime.Now.Subtract(beforeWarmup));
                var remainingMinutes = Math.Floor(remainingTime.TotalMinutes);
                var remainingSeconds = Math.Floor(remainingTime.TotalSeconds) % 60;

                Console.WriteLine("Remaining time: {0} minutes, {1} seconds.", remainingMinutes, remainingSeconds);
            }

            Console.WriteLine("Warm up completed");
        }
        catch (Exception ex)
        {
            Console.WriteLine("Error: " + ex.ToString());
            return 1;
        }
        return 0;
    }
}
Go to source

source

"""
A basic warm-up method for a Zivid camera with specified time and capture cycle.

The sample uses Capture Assistant unless a path to YAML Camera Settings is passed.
"""

import argparse
from datetime import datetime, timedelta
from pathlib import Path
from time import sleep

import zivid


def _options() -> argparse.Namespace:
    """Function to read user arguments.

    Returns:
        Arguments from user

    """
    parser = argparse.ArgumentParser(description=__doc__)

    parser.add_argument(
        "--settings-path",
        required=False,
        help="Path to the YML file that contains camera settings",
    )

    parser.add_argument(
        "--capture-cycle",
        required=False,
        type=float,
        default=5.0,
        help="Capture cycle in seconds",
    )

    return parser.parse_args()


def _load_or_suggest_settings(camera: zivid.Camera, settings_path: str) -> zivid.Settings:
    """Load settings from YML file or find them with the assisted capture

    Args:
        camera: Zivid camera
        settings_path: Path to the YML file that contains camera settings

    Returns:
        Camera Settings

    """

    if settings_path:
        print("Loading settings from file")
        return zivid.Settings.load(Path(settings_path))
    print("Getting camera settings from capture assistant")
    suggest_settings_parameters = zivid.capture_assistant.SuggestSettingsParameters(
        max_capture_time=timedelta(milliseconds=1000),
        ambient_light_frequency=zivid.capture_assistant.SuggestSettingsParameters.AmbientLightFrequency.none,
    )
    return zivid.capture_assistant.suggest_settings(camera, suggest_settings_parameters)


def _main() -> None:
    user_options = _options()
    app = zivid.Application()

    print("Connecting to camera")
    camera = app.connect_camera()
    warmup_time = timedelta(minutes=10)
    capture_cycle = timedelta(seconds=user_options.capture_cycle)
    settings = _load_or_suggest_settings(camera, user_options.settings_path)

    before_warmup = datetime.now()

    print(f"Starting warm up for {warmup_time} minutes")
    while (datetime.now() - before_warmup) < warmup_time:
        before_capture = datetime.now()
        camera.capture(settings)
        after_capture = datetime.now()

        duration = after_capture - before_capture

        if duration.seconds <= capture_cycle.seconds:
            sleep(capture_cycle.seconds - duration.seconds)
        else:
            print(
                "Your capture time is longer than your desired capture cycle. \
                 Please increase the desired capture cycle."
            )

        remaining_time = warmup_time - (datetime.now() - before_warmup)
        remaining_time_minutes = remaining_time.seconds // 60
        remaining_time_seconds = remaining_time.seconds % 60
        print(f"Remaining time: {remaining_time_minutes} minutes, {remaining_time_seconds} seconds.")

    print("Warm up completed")


if __name__ == "__main__":
    _main()

To warm up your camera, you can run our code sample, providing cycle time and path to your camera settings.

Sample: warmup.py

python /path/to/warmup.py --settings-path /path/to/settings.yml --capture-cycle 6.0