机器人解决方案

AI视觉库存机器人

基于视觉技术的自主库存管理。

 

AI视觉盘点机器人是一款自主移动机器人,它利用AI摄像头和计算机视觉技术进行库存盘点,而非依赖RFID标签。它能够自主穿行于货架通道之间,实时识别商品、书籍、标签及货架位置,在机上验证所识别的内容,并将结果同步至云平台——该机器人全天候运行,其盘点速度比人工盘点快达90%。

AI视觉

先进的AI摄像头能够精准识别产品、包装箱、标签和货架位置。

自动驾驶与智能

SLAM导航、避障和自主充电,实现全天候运行。

库存智能

通过实时数据采集与分析,确保库存和报告的准确性。

云连接

用于远程监控、报告和系统管理的安全云平台。

已扫描的物品0
放错地方了0
缺失0
状态正在扫描
扫描行为的示意图——非实时数据
/* ---------- palette + sizing (edit these) ---------- */ .stockbot{ --sb-height: 320px; --sb-bg: #F6F5F1; /* aisle / page ground */ --sb-floor: #E7E4DC; /* floor band */ --sb-line: #DEDBD1; /* borders */ --sb-shelf: #BEBAAC; /* shelving steel */ --sb-shelf-2: #A9A497; /* shelf edge / uprights */ --sb-teal: #013E49; /* HKC petrol — robot detail, counted marks */ --sb-teal-soft: #7FA7B0; --sb-gold: #D69D46; /* HKC gold — scan band, recognition boxes */ --sb-gold-deep: #8A6420; --sb-ink: #0B2027; --sb-ink-2: #4B5A61; --sb-ink-3: #7D8B90; --sb-surface: #FFFFFF; /* stats bar, robot body */ /* stock item tones */ --sb-i1: #C9B99B; --sb-i2: #B4A488; --sb-i3: #D8CDB6; --sb-i4: #9FA9A4; --sb-i5: #C2CBC9; --sb-font: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; --sb-mono: ui-monospace, SFMono-Regular, Menlo, Consolas, "Courier New", monospace; } @media (prefers-color-scheme: dark){ .stockbot[data-scheme="auto"]{ --sb-bg: #06171C; --sb-floor: #0B2229; --sb-line: #17343C; --sb-shelf: #2C4A52; --sb-shelf-2: #3A5C65; --sb-teal: #4FB8C9; --sb-teal-soft: #2A6270; --sb-gold: #E8B765; --sb-gold-deep: #E8B765; --sb-ink: #E7EFF0; --sb-ink-2: #9DB2B7; --sb-ink-3: #74898F; --sb-surface: #0C232A; --sb-i1: #7A6D55; --sb-i2: #8B7C61; --sb-i3: #665C48; --sb-i4: #52605E; --sb-i5: #45514F; } } .stockbot[data-scheme="dark"]{ --sb-bg: #06171C; --sb-floor: #0B2229; --sb-line: #17343C; --sb-shelf: #2C4A52; --sb-shelf-2: #3A5C65; --sb-teal: #4FB8C9; --sb-teal-soft: #2A6270; --sb-gold: #E8B765; --sb-gold-deep: #E8B765; --sb-ink: #E7EFF0; --sb-ink-2: #9DB2B7; --sb-ink-3: #74898F; --sb-surface: #0C232A; --sb-i1: #7A6D55; --sb-i2: #8B7C61; --sb-i3: #665C48; --sb-i4: #52605E; --sb-i5: #45514F; } /* ---------- structure ---------- */ .stockbot, .stockbot *{ box-sizing: border-box; } .stockbot{ width: 100%; font-family: var(--sb-font); } .stockbot__frame{ border: 1px solid var(--sb-line); border-radius: 14px; background: var(--sb-bg); overflow: hidden; } .stockbot__canvas{ display: block; width: 100%; height: var(--sb-height); max-width: 100%; } .stockbot__bar{ display: flex; flex-wrap: wrap; align-items: center; border-top: 1px solid var(--sb-line); background: var(--sb-surface); } .stockbot__stat{ display: flex; align-items: baseline; gap: 9px; padding: 11px 20px; border-right: 1px solid var(--sb-line); font-family: var(--sb-mono); font-size: 11px; line-height: 1.4; letter-spacing: .11em; text-transform: uppercase; color: var(--sb-ink-3); } .stockbot__stat b{ font-size: 14px; font-weight: 600; letter-spacing: .02em; color: var(--sb-ink); font-variant-numeric: tabular-nums; } .stockbot__stat--live b{ color: var(--sb-gold-deep); } .stockbot__note{ margin-left: auto; padding: 11px 20px; font-family: var(--sb-mono); font-size: 10px; line-height: 1.4; letter-spacing: .08em; text-transform: uppercase; color: var(--sb-ink-3); } @media (max-width: 820px){ .stockbot__note{ margin-left: 0; width: 100%; border-top: 1px solid var(--sb-line); } .stockbot__stat{ padding: 10px 14px; } } (function () { 'use strict'; function initAll(){ var n = document.querySelectorAll('.stockbot'); for (var i = 0; i < n.length; i++) init(n[i]); } function init(root){ if (root.getAttribute('data-sb-ready') === '1') return; root.setAttribute('data-sb-ready', '1'); var cv = root.querySelector('.stockbot__canvas'); if (!cv || !cv.getContext) return; var ctx = cv.getContext('2d'); var elScanned = root.querySelector('[data-sb="scanned"]'); var elFlagged = root.querySelector('[data-sb="flagged"]'); var elMissing = root.querySelector('[data-sb="missing"]'); var elStatus = root.querySelector('[data-sb="status"]'); var motionQuery = window.matchMedia('(prefers-reduced-motion: reduce)'); var W = 0, H = 0, dpr = 1; var floorY = 0, shelfTop = 0, rows = 3, rowH = 0; var items = [], uprights = []; var bot = null; var scanned = 0, flagged = 0, missing = 0; var rafId = null, last = 0, running = false; var C = {}, MODE = 'vision'; function readTokens(){ var s = getComputedStyle(root); function g(n){ return s.getPropertyValue(n).trim(); } C = { bg:g('--sb-bg'), floor:g('--sb-floor'), line:g('--sb-line'), shelf:g('--sb-shelf'), shelf2:g('--sb-shelf-2'), teal:g('--sb-teal'), tealSoft:g('--sb-teal-soft'), gold:g('--sb-gold'), goldDeep:g('--sb-gold-deep'), ink:g('--sb-ink'), ink2:g('--sb-ink-2'), ink3:g('--sb-ink-3'), surface:g('--sb-surface'), items:[g('--sb-i1'),g('--sb-i2'),g('--sb-i3'),g('--sb-i4'),g('--sb-i5')], mono:g('--sb-mono') || 'monospace' }; MODE = (root.getAttribute('data-mode') || 'vision').toLowerCase(); if (MODE !== 'rfid') MODE = 'vision'; } function rr(x,y,w,h,r){ r = Math.min(r, Math.abs(w)/2, Math.abs(h)/2); ctx.beginPath(); ctx.moveTo(x+r,y); ctx.arcTo(x+w,y,x+w,y+h,r); ctx.arcTo(x+w,y+h,x,y+h,r); ctx.arcTo(x,y+h,x,y,r); ctx.arcTo(x,y,x+w,y,r); ctx.closePath(); } function build(){ floorY = H - Math.max(20, H * 0.08); shelfTop = Math.max(14, H * 0.06); rows = H < 240 ? 3 : 4; rowH = (floorY - shelfTop) / rows; // uprights every ~170px uprights = []; var step = Math.max(150, W / Math.max(2, Math.round(W / 190))); for (var ux = 0; ux <= W + step; ux += step) uprights.push(ux); items = []; for (var r = 0; r < rows; r++){ var boardY = shelfTop + (r + 1) * rowH; // shelf board the row sits on var x = 8; while (x W - 8) break; var gap = 2 + Math.random() * 3; // ~7% of slots are empty — these become "missing" when scanned var empty = Math.random() < 0.07; var h = rowH * (0.52 + Math.random() * 0.34); items.push({ x: x, w: w, h: h, row: r, top: boardY - 3 - h, col: C.items[(Math.random() * C.items.length) | 0], empty: empty, // ~6% of present items are misplaced misplaced: (!empty && Math.random() scan -> done t: 0 }); x += w + gap; } } bot = { x: -60, speed: 52 + Math.random() * 10, alpha: 0, h: (floorY - shelfTop) * 0.92 }; } function reset(){ build(); if (elStatus) elStatus.textContent = 'Scanning'; } function scanX(){ return bot.x + 26; } function update(dt){ bot.x += bot.speed * dt; bot.alpha = Math.min(1, bot.alpha + dt * 2); var sx = scanX(); for (var i = 0; i = it.x + it.w * 0.5){ it.state = 'scan'; it.t = 0; if (it.empty){ missing++; } else { scanned++; if (it.misplaced) flagged++; } } else if (it.state === 'scan'){ it.t += dt / 0.55; if (it.t >= 1){ it.t = 1; it.state = 'done'; } } } if (bot.x > W + 70){ scanned = 0; flagged = 0; missing = 0; reset(); } } function drawShelving(){ // floor ctx.fillStyle = C.floor; ctx.fillRect(0, floorY, W, H - floorY); ctx.strokeStyle = C.shelf2; ctx.globalAlpha = .5; ctx.beginPath(); ctx.moveTo(0, floorY + .5); ctx.lineTo(W, floorY + .5); ctx.stroke(); ctx.globalAlpha = 1; // shelf boards ctx.fillStyle = C.shelf; for (var r = 0; r <= rows; r++){ var y = shelfTop + r * rowH; ctx.fillRect(0, y, W, 3); } // uprights ctx.fillStyle = C.shelf2; for (var i = 0; i < uprights.length; i++){ ctx.fillRect(uprights[i], shelfTop, 4, floorY - shelfTop); } // bay labels ctx.fillStyle = C.ink3; ctx.font = '600 8px ' + C.mono; ctx.textAlign = 'left'; ctx.textBaseline = 'top'; for (var j = 0; j < uprights.length - 1; j++){ ctx.fillText('A' + (j + 1), uprights[j] + 8, shelfTop + 5); } } function drawItems(){ for (var i = 0; i < items.length; i++){ var it = items[i]; if (!it.empty){ ctx.fillStyle = it.col; rr(it.x, it.top, it.w, it.h, 1.5); ctx.fill(); // spine highlight ctx.fillStyle = C.surface; ctx.globalAlpha = .22; ctx.fillRect(it.x + 1.5, it.top + 2, Math.max(1, it.w * 0.22), it.h - 4); ctx.globalAlpha = 1; } // recognition annotation if (it.state === 'scan'){ var e = 1 - Math.pow(1 - it.t, 2); ctx.globalAlpha = 0.35 + 0.65 * (1 - it.t); ctx.strokeStyle = it.empty ? C.ink3 : C.gold; ctx.lineWidth = 1.4; if (it.empty) ctx.setLineDash([3, 3]); var pad = 2.5 * (1 - e) + 1.5; rr(it.x - pad, it.top - pad, it.w + pad * 2, it.h + pad * 2, 2); ctx.stroke(); ctx.setLineDash([]); ctx.globalAlpha = 1; } if (it.state === 'done'){ if (it.empty){ // missing slot ctx.strokeStyle = C.ink3; ctx.globalAlpha = .55; ctx.lineWidth = 1; ctx.setLineDash([3, 3]); rr(it.x, it.top, it.w, it.h, 2); ctx.stroke(); ctx.setLineDash([]); ctx.globalAlpha = 1; } else if (it.misplaced){ // flagged: persistent gold outline + marker dot ctx.strokeStyle = C.gold; ctx.lineWidth = 1.3; rr(it.x - 1.5, it.top - 1.5, it.w + 3, it.h + 3, 2); ctx.stroke(); ctx.fillStyle = C.gold; ctx.beginPath(); ctx.arc(it.x + it.w / 2, it.top - 5, 2, 0, Math.PI * 2); ctx.fill(); } else { // counted: small teal tick under the item ctx.fillStyle = C.teal; ctx.globalAlpha = .8; ctx.fillRect(it.x, it.top + it.h + 1.5, it.w, 1.4); ctx.globalAlpha = 1; } } } } function drawScan(){ var sx = scanX(); if (sx W + 30) return; var bandW = MODE === 'rfid' ? 96 : 62; var top = shelfTop, bot2 = floorY; var grad = ctx.createLinearGradient(sx - bandW / 2, 0, sx + bandW / 2, 0); grad.addColorStop(0, 'rgba(0,0,0,0)'); grad.addColorStop(0.5, C.gold); grad.addColorStop(1, 'rgba(0,0,0,0)'); ctx.globalAlpha = MODE === 'rfid' ? .13 : .18; ctx.fillStyle = grad; ctx.fillRect(sx - bandW / 2, top, bandW, bot2 - top); ctx.globalAlpha = 1; // leading edge ctx.strokeStyle = C.gold; ctx.globalAlpha = .75; ctx.lineWidth = 1.2; ctx.beginPath(); ctx.moveTo(sx, top); ctx.lineTo(sx, bot2); ctx.stroke(); ctx.globalAlpha = 1; } function drawBot(){ var baseW = 34, baseH = 13; var x = bot.x; var y = floorY; var topY = y - bot.h; ctx.save(); ctx.globalAlpha = bot.alpha; // ground glow ctx.fillStyle = C.teal; ctx.globalAlpha = bot.alpha * .12; ctx.beginPath(); ctx.ellipse(x, y + 2, baseW * 0.85, 5, 0, 0, Math.PI * 2); ctx.fill(); ctx.globalAlpha = bot.alpha; // sensing rays from the head toward the shelves var headY = topY + 10; ctx.strokeStyle = MODE === 'rfid' ? C.gold : C.teal; ctx.globalAlpha = bot.alpha * .45; ctx.lineWidth = 1; if (MODE === 'rfid'){ for (var k = 1; k <= 3; k++){ ctx.beginPath(); ctx.arc(x + 8, y - bot.h * 0.5, 12 + k * 11, -Math.PI * 0.42, Math.PI * 0.42); ctx.stroke(); } } else { ctx.beginPath(); ctx.moveTo(x + 6, headY); ctx.lineTo(scanX() + 22, shelfTop + 6); ctx.moveTo(x + 6, headY); ctx.lineTo(scanX() + 22, floorY - 6); ctx.stroke(); } ctx.globalAlpha = bot.alpha; // mast ctx.strokeStyle = C.ink2; ctx.lineWidth = 4; ctx.lineCap = 'round'; ctx.beginPath(); ctx.moveTo(x, topY + 26); ctx.lineTo(x, y - baseH - 26); ctx.stroke(); // camera head ctx.fillStyle = C.ink; rr(x - 5, topY, 10, 18, 2.5); ctx.fill(); ctx.fillStyle = MODE === 'rfid' ? C.gold : C.teal; ctx.beginPath(); ctx.arc(x, topY + 9, 2.4, 0, Math.PI * 2); ctx.fill(); // gold collar ctx.fillStyle = C.surface; ctx.strokeStyle = C.gold; ctx.lineWidth = 2; ctx.beginPath(); ctx.ellipse(x, topY + 34, 15, 8, 0, 0, Math.PI * 2); ctx.fill(); ctx.stroke(); // tapered body var bodyTop = topY + 40; var bodyBot = y - baseH - 1; ctx.beginPath(); ctx.moveTo(x - 8, bodyTop); ctx.quadraticCurveTo(x - 10, (bodyTop + bodyBot) / 2, x - 19, bodyBot); ctx.lineTo(x + 19, bodyBot); ctx.quadraticCurveTo(x + 10, (bodyTop + bodyBot) / 2, x + 8, bodyTop); ctx.closePath(); ctx.fillStyle = C.surface; ctx.fill(); ctx.strokeStyle = C.shelf2; ctx.lineWidth = 1; ctx.stroke(); // base + gold ring ctx.fillStyle = C.surface; rr(x - baseW / 2, y - baseH, baseW, baseH, 5); ctx.fill(); ctx.strokeStyle = C.gold; ctx.lineWidth = 2; rr(x - baseW / 2, y - baseH, baseW, baseH, 5); ctx.stroke(); ctx.fillStyle = C.teal; ctx.fillRect(x - 7, y - baseH / 2 - 1, 14, 2); ctx.restore(); } function draw(){ ctx.clearRect(0, 0, W, H); ctx.fillStyle = C.bg; ctx.fillRect(0, 0, W, H); drawShelving(); drawItems(); drawScan(); drawBot(); } function syncStats(){ if (elScanned && elScanned.textContent !== String(scanned)) elScanned.textContent = scanned.toLocaleString('en-US'); if (elFlagged && elFlagged.textContent !== String(flagged)) elFlagged.textContent = String(flagged); if (elMissing && elMissing.textContent !== String(missing)) elMissing.textContent = String(missing); } function frame(now){ if (!running) return; var dt = Math.min(0.05, (now - last) / 1000 || 0); last = now; update(dt); draw(); syncStats(); rafId = requestAnimationFrame(frame); } function start(){ if (running || motionQuery.matches || !W) return; running = true; last = performance.now(); rafId = requestAnimationFrame(frame); } function stop(){ running = false; if (rafId) cancelAnimationFrame(rafId); rafId = null; } function staticFrame(){ // pose a representative still: robot mid-run, shelves part-scanned bot.x = W * 0.46; bot.alpha = 1; var sx = scanX(); scanned = 0; flagged = 0; missing = 0; for (var i = 0; i < items.length; i++){ var it = items[i]; if (it.x + it.w * 0.5 < sx){ it.state = 'done'; it.t = 1; if (it.empty) missing++; else { scanned++; if (it.misplaced) flagged++; } } } draw(); syncStats(); if (elStatus) elStatus.textContent = 'Scanning'; } function resize(){ var r = cv.getBoundingClientRect(); if (!r.width) return; dpr = Math.min(window.devicePixelRatio || 1, 2); cv.width = Math.round(r.width * dpr); cv.height = Math.round(r.height * dpr); ctx.setTransform(dpr, 0, 0, dpr, 0, 0); W = r.width; H = r.height; readTokens(); scanned = 0; flagged = 0; missing = 0; build(); if (motionQuery.matches) staticFrame(); else draw(); } var rt; window.addEventListener('resize', function(){ clearTimeout(rt); rt = setTimeout(resize, 140); }); var darkQuery = window.matchMedia('(prefers-color-scheme: dark)'); function repaint(){ readTokens(); if (!running) draw(); } if (darkQuery.addEventListener) darkQuery.addEventListener('change', repaint); if (window.MutationObserver){ new MutationObserver(function(){ readTokens(); if (!running) draw(); }) .observe(root, { attributes: true, attributeFilter: ['data-scheme', 'data-mode'] }); } if (motionQuery.addEventListener){ motionQuery.addEventListener('change', function(){ if (motionQuery.matches){ stop(); staticFrame(); } else { start(); } }); } document.addEventListener('visibilitychange', function(){ if (document.hidden) stop(); else start(); }); if ('IntersectionObserver' in window){ new IntersectionObserver(function(entries){ if (entries[0].isIntersecting) start(); else stop(); }, { threshold: 0.02 }).observe(cv); } function boot(){ resize(); if (!motionQuery.matches) start(); } if (document.fonts && document.fonts.ready) document.fonts.ready.then(boot).catch(boot); else boot(); } if (document.readyState === 'loading'){ document.addEventListener('DOMContentLoaded', initAll); } else { initAll(); } })();

什么是人工智能视觉盘点机器人?

人工智能视觉盘点机器人是一种自主移动机器人,它利用摄像头和计算机视觉技术对库存进行清点和核验,而不是通过读取RFID标签,也不是由人工手持扫描仪在货架间走动进行盘点。

传统的库存盘点存在三个始终无法解决的问题:需要人工操作、速度慢且结果不一致。由于每次盘点都需要耗费一个班次的人力,因此盘点通常每季度进行一次,而非持续进行;等到数据汇总完成时,这些数据早已过时。

AI视觉盘点机器人消除了人工干预。它会在夜间或换班期间执行预定任务,识别每个货架上的物品,标记缺货或摆放错误的商品,并在卖场开门前生成报告。

其关键区别在于,该方法无需RFID基础设施。RFID盘点虽然快速准确,但前提是每个物品都必须贴有标签,且标签系统需要得到维护。对于未贴标签的藏品——或者对每个物品贴标签在经济上不划算的情况——这构成了一个难以逾越的门槛。

计算机视觉技术能够识别现有的信息:产品本身、包装盒、印刷标签、条形码以及货架位置。在机器人开始清点库存之前,无需对库存进行任何处理。

机器人正在扫描书架
HOW

AI视觉盘点机器人是如何工作的

每次盘点都遵循相同的六步流程,从计划任务到生成报告——整个过程中,过道里始终没有人。

1.

任务设置

设置盘点任务,选择需要覆盖的区域或扫描组,并安排机器人运行的时间。

3.

AI扫描与识别

该人工智能视觉系统在移动过程中实时扫描货架,并识别商品、条形码和标签。

5.

实时云同步

经过验证的库存数据会即时上传至云平台,因此在机器人仍在工作时,即可获取结果。

2.

自主导航

该机器人利用SLAM技术自主在环境中导航,避开障碍物,并优化其在过道中的行进路线。

4.

数据验证

采集到的数据会在机器人上进行验证,以确保其准确性和完整性,然后才会将数据传输出去。

6.

报告与洞察

该平台将扫描结果转换为库存报告、缺货和错放商品清单、单品级详细信息以及Excel导出文件。

益处

主要优势

机器人运行后,现场会发生哪些变化?

高精度

AI视觉技术确保每次通过时都能实现精准的识别和验证。

节省时间

比人工盘点快达90%。

降低成本

降低劳动力成本,并将人为错误降至最低。

安全可靠

多传感器保护,确保在动态环境中安全运行。

实时可视性

随时随地查看实时库存状况。

WHERE

专为现代化设施设计

凡是存放在货架上、需要经常清点且从经济角度来看不值得贴上标签的库存。

图书馆与档案馆

无需关闭楼层即可进行上架核对和馆藏核查。该平台支持通过条形码定位馆藏和楼层平面图搜索,以及错放馆藏检测——这两项工作通常占用了上架工作的绝大部分时间。

仓储与配送

在不占用拣货人员的情况下,对整个货架进行循环盘点,并将单品级报告直接导出到Excel或上游系统。

教育与机构

校园图书馆、资源中心和设备仓库,藏量庞大,但工作人员队伍规模较小。

零售与超市

采用持续的货架盘点而非季度盘点,在顾客发现缺货之前,就对缺货和错放的商品进行标记。

制造商店

在零部件和耗材仓库中,准确性直接关系到生产线的可用性,而缺失一个零件所造成的损失远高于其本身的价格。

资产密集型设施

巡逻管理功能使该机器人在完成库存任务的间隙,还能作为定时楼层巡查平台使用。

联系我们

请告诉我们任务是什么,而不是机器人

请描述您希望实现自动化处理的工作——具体需要搬运什么、频率如何、距离多远,以及目前需要多少人手。这些信息足以让HKC判断哪种机器人适合,方案是否可行,以及试点项目将涉及哪些内容。

图像

电子邮件

contact_hkcgroup@hkc.net

图像

致电我们

+852 2527 8822

图像

办公室地址

香港黄竹坑道29号 维塔大厦B座14楼