Robotic Solutions

LIBRA Stock Take Robot

The LIBRA Stock Take Robot is an autonomous mobile robot that counts and audits stock on its own, RFID tag reading — with SLAM navigation. It scans shelves on a schedule you set, and returns a report telling you not only what is there, but what is in the wrong position and what is suspected missing.

RFID

reading

Scheduled

Runs as often as you require, unattended

SLAM

Autonomous navigation & obstacle avoidance

.stockbot{ --sb-height: 300px; --sb-bg:#F4F6F9; --sb-floor:#E4EAF2; --sb-line:#DCE3EC; --sb-shelf:#B7C2D2; --sb-shelf-2:#9AA8BC; --sb-teal:#0387D1; --sb-teal-soft:#7FBEE4; --sb-gold:#157F3C; --sb-gold-deep:#157F3C; --sb-ink:#0A1B33; --sb-ink-2:#4A5A72; --sb-ink-3:#7C8AA0; --sb-surface:#FFFFFF; --sb-i1:#C3CCDA; --sb-i2:#AEBACB; --sb-i3:#D5DCE7; --sb-i4:#9FB0C6; --sb-i5:#BCC7D6; --sb-font:"IBM Plex Sans","Segoe UI",Helvetica,Arial,sans-serif; --sb-mono:"Fira Mono",ui-monospace,Consolas,monospace; } @media (prefers-color-scheme: dark){ :root:not([data-theme="light"]) .stockbot{ --sb-bg:#061225; --sb-floor:#0B1B33; --sb-line:#1D3050; --sb-shelf:#26405F; --sb-shelf-2:#33567C; --sb-teal:#4FB3EE; --sb-teal-soft:#2A6B96; --sb-gold:#4ADE80; --sb-gold-deep:#4ADE80; --sb-ink:#E8EEF7; --sb-ink-2:#9EAEC6; --sb-ink-3:#71829C; --sb-surface:#0D1D35; --sb-i1:#33465F; --sb-i2:#3D5271; --sb-i3:#2A3A50; --sb-i4:#465873; --sb-i5:#38495F; } } :root[data-theme="dark"] .stockbot{ --sb-bg:#061225; --sb-floor:#0B1B33; --sb-line:#1D3050; --sb-shelf:#26405F; --sb-shelf-2:#33567C; --sb-teal:#4FB3EE; --sb-teal-soft:#2A6B96; --sb-gold:#4ADE80; --sb-gold-deep:#4ADE80; --sb-ink:#E8EEF7; --sb-ink-2:#9EAEC6; --sb-ink-3:#71829C; --sb-surface:#0D1D35; --sb-i1:#33465F; --sb-i2:#3D5271; --sb-i3:#2A3A50; --sb-i4:#465873; --sb-i5:#38495F; } .stockbot,.stockbot *{box-sizing:border-box} .stockbot{width:100%;font-family:var(--sb-font)} .stockbot__frame{border:1px solid var(--sb-line);border-radius:13px;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:700;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} }
Items read0
Wrong position0
Suspected missing0
StatusScanning
Illustration of scanning behaviour — not live data
(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,floorY=0,shelfTop=0,rows=3,rowH=0; var items=[],uprights=[],bot=null; var scanned=0,flagged=0,missing=0,rafId=null,last=0,running=false,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=[]; 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, x=8; while(xW-8) break; var gap=2+Math.random()*3; 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,misplaced:(!empty&&Math.random()<0.06),state:'pending',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(){ 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; ctx.fillStyle=C.shelf; for(var r=0;r<=rows;r++){ctx.fillRect(0,shelfTop+r*rowH,W,3);} ctx.fillStyle=C.shelf2; for(var i=0;i<uprights.length;i++){ctx.fillRect(uprights[i],shelfTop,4,floorY-shelfTop);} ctx.fillStyle=C.ink3; ctx.font='500 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(); 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; } 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.teal; 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){ 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){ ctx.strokeStyle=C.teal; 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.teal; ctx.beginPath(); ctx.arc(it.x+it.w/2,it.top-5,2,0,Math.PI*2); ctx.fill(); } else { ctx.fillStyle=C.gold; ctx.globalAlpha=.85; ctx.fillRect(it.x,it.top+it.h+1.5,it.w,1.4); ctx.globalAlpha=1; } } } } function drawScan(){ var sx=scanX(); if(sxW+30) return; var bandW=MODE==='rfid'?96:62, 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.teal); grad.addColorStop(1,'rgba(0,0,0,0)'); ctx.globalAlpha=MODE==='rfid'?.14:.18; ctx.fillStyle=grad; ctx.fillRect(sx-bandW/2,top,bandW,bot2-top); ctx.globalAlpha=1; ctx.strokeStyle=C.teal; 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,x=bot.x,y=floorY,topY=y-bot.h; ctx.save(); ctx.globalAlpha=bot.alpha; 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; var headY=topY+10; ctx.strokeStyle=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; 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(); ctx.fillStyle=C.ink; rr(x-5,topY,10,18,2.5); ctx.fill(); ctx.fillStyle=C.teal; ctx.beginPath();ctx.arc(x,topY+9,2.4,0,Math.PI*2);ctx.fill(); ctx.fillStyle=C.surface; ctx.strokeStyle=C.teal; ctx.lineWidth=2; ctx.beginPath();ctx.ellipse(x,topY+34,15,8,0,0,Math.PI*2);ctx.fill();ctx.stroke(); var bodyTop=topY+40,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(); ctx.fillStyle=C.surface; rr(x-baseW/2,y-baseH,baseW,baseH,5); ctx.fill(); ctx.strokeStyle=C.teal; ctx.lineWidth=2; rr(x-baseW/2,y-baseH,baseW,baseH,5); ctx.stroke(); ctx.fillStyle=C.ink2; 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(){ 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(repaint).observe(root,{attributes:true,attributeFilter:['data-scheme','data-mode']}); new MutationObserver(repaint).observe(document.documentElement,{attributes:true,attributeFilter:['data-theme']}); } 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(e){ if(e[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(); })();

What is an LIBRA stock take robot?

An LIBRA stock take robot is an autonomous mobile robot that performs inventory counts by driving the aisles itself, reading RFID tags and recognising items, then uploading the results to a cloud system.

RFID processing has brought large improvements to tracking merchandise across the retail supply chain, and the cost of the technology has fallen sharply in recent years. The benefits are straightforward: it virtually eliminates human error in stock tracking and gives far higher inventory visibility.

Traditional inventory-taking means a person walking the aisles with a handheld reader, or counting items by hand. Both are slow, and both are only as consistent as the person doing them at the end of a long shift.

An LIBRA stock take robot goes a step further than a handheld reader: it lets you programme regular, automated inventory tracking and data collection, rather than scheduling a count as a project each time.

Because the robot works unattended, the constraint on counting frequency stops being labour. Sites that counted quarterly can count weekly, and discrepancies surface while they are still cheap to fix.

Challenges

Store and inventory

Six problems that come up repeatedly in tracking products in-store and managing inventory — and that a scheduled robot count addresses directly.

LIBRA stock take robot

Stock data accuracy

Without accurate inventory it is impossible to understand exactly what is in stock at any given moment.

01

Maximising space in warehouses

Inventory management platforms help you understand free space in warehouses, ready for deliveries of new stock.

04

Inconsistent tracking of items

Manual inventory tracking procedures take time and are prone to errors.

02

Overstocking of products

Overstocking leads to cash flow problems and storage problems such as stock damage.

05

Inventory documentation

Using paperwork to document inventory does not scale easily across multiple stores.

03

Slow and inefficient processes

Inefficient, time-consuming and low-tech operating procedures become difficult to maintain as operations expand.

06
HOW

How the LIBRA Stock Take Robot works

The robot carries RFID antennas. As it moves within range of a shelf it reads the tags, scans the images, and updates its records in the cloud.

1.

SLAM navigation

Lidar and cameras let the robot perform SLAM — simultaneous localisation of its own position and mapping of the area. It avoids obstacles including people and furniture, docks and charges itself, and locates itself inside a store or warehouse continuously as it collects data from each tag.

2.

Locating tags by antenna timing

The reader emits radio waves through several antennas. Tags bounce the signal back and the same antennas receive it. By measuring the distance estimated from each antenna's reception time, the reader calculates the approximate location of every tag relative to the robot — which is what makes “wrong position” detection possible.

Benefits

Benefits

What changes once counting stops being a manual job.

Popularity trends identification

Regularly programmed inventories reveal popularity trends, including data on the volumes of books being borrowed — insight a periodic count cannot give you.

01

Reduce labour cost

The robot moves around the area itself, so robotic stock-taking removes the labour cost of walking the aisles with a handheld reader.

02

Free staff for higher-value work

Doing inventories by robot frees staff for work that needs a person — and, in a library, gives them more time to spend with patrons.

03
WHERE

Applications

Proven across four environments where stock sits on shelves and needs counting often.

Library

The stock take robot enhances libraries by automating inventory management, increasing accuracy, and freeing staff to focus on engaging with patrons and improving services.

Archives & records

Large tagged collections where a full manual audit is impractical, and where position accuracy matters as much as presence.

Warehouse

Cycle counting across racking without pulling staff off picking.

Multi-site operations

Cloud reporting means several sites are counted to the same method and compared on the same basis, rather than each keeping its own paperwork.

Let's Talk

Tell us the task, not the robot

Describe the work you want automated — what moves, how often, how far, and how many people it takes today. That is enough for HKC to say which robot fits, whether the numbers work, and what a pilot would involve.

image

Email

contact_hkcgroup@hkc.net

image

Call Us

+852 2527 8822

image

Office Address

14/F., Block B, Vita Tower, 29 Wong Chuk Hang Road, Hong Kong