[Challenge #02 – ํ•ด์„คํŽธ] AGV๋Š” ๋ช‡ ๋Œ€๊ฐ€ ์ ๋‹นํ–ˆ์„๊นŒ?

๐Ÿงช [Challenge #02 – ํ•ด์„คํŽธ] AGV๋Š” ๋ช‡ ๋Œ€๊ฐ€ ์ ๋‹นํ–ˆ์„๊นŒ?

์ƒ์‚ฐ์„ฑ๊ณผ ํšจ์œจ ์‚ฌ์ด, ์ตœ์ ์˜ AGV ์ˆ˜๋ฅผ ์ฐพ์•„๊ฐ€๋Š” ์‹œ๋ฎฌ๋ ˆ์ด์…˜ ๋ถ„์„


โš™๏ธ ๋ชจ๋ธ๋ง ์ง„ํ–‰ ๊ณผ์ •

1๏ธโƒฃ ๋ ˆ์ด์•„์›ƒ ๋ฐฐ์น˜ ๋ฐ ๊ธฐ๋ณธ ์„ธํŒ…

  • ๊ณต์ • ํ๋ฆ„: Start → B zone (Station B) → A zone (Station A) → End
  • ๊ฐ ๊ณต์ • ์•ž์— Marker ๊ฐ์ฒด ๋ฐฐ์น˜ → AGV์˜ Pick/Drop ์œ„์น˜ ์ง€์ •
  • ์šด์†ก ๊ฒฝ๋กœ:
    • Track ๋˜๋Š” Line ๊ฐ์ฒด๋ฅผ ์ด์šฉํ•˜์—ฌ AGV์˜ ์ด๋™ ๊ฒฝ๋กœ ๊ตฌ์„ฑ
    • AGVPool์—์„œ ์ถœ๋ฐœ → Marker → ๋‹ค์Œ Marker → ๋ณต๊ท€ ์ˆœํ™˜
  • ๊ณต๊ฐ„ ๊ตฌ์กฐ:
    • ํšŒ์ „ ๋ฐ˜๊ฒฝ 0m → AGV๊ฐ€ ์ œ์ž๋ฆฌ ํšŒ์ „ ๊ฐ€๋Šฅ
    • ์ข์€ ๊ณต๊ฐ„ ๋‚ด ์ตœ๋‹จ ๋™์„  ๊ตฌํ˜„ ์šฉ์ด

2๏ธโƒฃ ๋กœ์ง ์ œ์ž‘

  • AGV ์ œ์–ด ๋ฐฉ์‹: AGVPool์—์„œ AGV ๋ช…๋ น ๋‹จ์ผ ๋ฐœํ–‰ (1ํšŒ์„ฑ ๋ช…๋ น)
  • ๊ฐ ๊ณต์ • ์™„๋ฃŒ ์‹œ:
    • Method ์‚ฌ์šฉํ•˜์—ฌ Source , A , B ์—์„œ ์ž‘์—… ๋ช…๋ น Queue ์ž…๋ ฅ
    • Source ์ž‘์—… Seq Queue ์ถ”๊ฐ€ - B ๊ฐ€ Source ๋‹ค์Œ ๊ณต์ •์ด๊ธฐ ๋•Œ๋ฌธ์— ํ•ด๋‹น Station ์ƒํƒœ๋ฅผ ๋ณด๊ณ  ๋ช…๋ น์„ ๋„ฃ๋Š”๋‹ค.
--Source exit ctrl

waituntil B_1.set = false or  B_2.set = false or  B_3.set = false -- Waituntil B1 Station Empty

if B_1.set = false
	B_1.set := true
elseif B_2.set = false
	B_2.set := true
else
	B_3.set := true
end

seq.push(?.name) -- Set Seq queue
seq.push("")

 

  • B , A ๊ตฌ์—ญ Station Logic
waituntil A_1.set = false or  A_2.set = false  or  A_3.set = false -- B only

seq.push(?.name)
seq.push("")
  • AMR seq ๋ณ„ ๋ช…๋ น ์ˆ˜ํ–‰ - Queue object , Seq_top variable object , observer ctrl
-- param attribute: string, oldValue, newValue: string
-- param attribute: string, oldValue: string
param newValue: string

var A :object

waituntil AGVPool.NumIdleAGVs > 0
var agv := agvPool.getIdleAGV
seq.pop
switch newValue
case ""
case "Source"
	agv.destination := O_M
	waituntil agv.destinationwasreached
	wait loadunloadTIme
	source.mu.move(agv)
	if B_1.empty = true
		agv.destination := B_1_M
		waituntil agv.destinationwasreached
		wait loadunloadTIme
		agv.mu.move(B_1)
	elseif B_2.empty = true
		agv.destination := B_2_M
		waituntil agv.destinationwasreached
		wait loadunloadTIme
		agv.mu.move(B_2)
	else
		agv.destination := B_3_M
		waituntil agv.destinationwasreached
		wait loadunloadTIme
		agv.mu.move(B_3)
	end
	agv.destination := AGVPool
	waituntil agv.destinationwasreached
case "A_1"
	agv.destination := A_1_M
	waituntil agv.destinationwasreached
	wait loadunloadTIme
	A_1.mu.move(agv)
	agv.destination := Marker
	waituntil agv.destinationwasreached
	wait loadunloadTIme
	agv.mu.move(Conveyor)
	agv.destination := AGVPool
	waituntil agv.destinationwasreached
	A_1.set := false
case "A_2"
	agv.destination := A_2_M
	waituntil agv.destinationwasreached
	wait loadunloadTIme
	A_2.mu.move(agv)
	agv.destination := Marker
	waituntil agv.destinationwasreached
	wait loadunloadTIme
	agv.mu.move(Conveyor)
	agv.destination := AGVPool
	waituntil agv.destinationwasreached
	A_2.set := false
case "A_3"
	agv.destination := A_3_M
	waituntil agv.destinationwasreached
	wait loadunloadTIme
	A_3.mu.move(agv)
	agv.destination := Marker
	waituntil agv.destinationwasreached
	wait loadunloadTIme
	agv.mu.move(Conveyor)
	agv.destination := AGVPool
	waituntil agv.destinationwasreached
	A_3.set := false
case "B_1"
	if A_1.set = false
		A_1.set := True
		A := A_1
	elseif A_2.set = false
		A_2.set := True
		A := A_2
	else
		A_3.set := True
		A := A_3
	end

	agv.destination := B_1_M
	waituntil agv.destinationwasreached
	wait loadunloadTIme
	B_1.mu.move(agv)
	if A = A_1
		agv.destination := A_1_M
		waituntil agv.destinationwasreached
		wait loadunloadTIme
		agv.mu.move(A_1)
	elseif A = A_2
		A_2.set := True
		agv.destination := A_2_M
		waituntil agv.destinationwasreached
		wait loadunloadTIme
		agv.mu.move(A_2)
	else
		A_3.set := True
		agv.destination := A_3_M
		waituntil agv.destinationwasreached
		wait loadunloadTIme
		agv.mu.move(A_3)
	end
	B_1.set := false
	agv.destination := AGVPool
	waituntil agv.destinationwasreached
case "B_2"
	if A_1.set = false
		A_1.set := True
		A := A_1
	elseif A_2.set = false
		A_2.set := True
		A := A_2
	else
		A_3.set := True
		A := A_3
	end

	agv.destination := B_2_M
	waituntil agv.destinationwasreached
	wait loadunloadTIme
	B_2.mu.move(agv)
	if A = A_1
		A_1.set := True
		agv.destination := A_1_M
		waituntil agv.destinationwasreached
		wait loadunloadTIme
		agv.mu.move(A_1)
	elseif A = A_2
		A_2.set := True
		agv.destination := A_2_M
		waituntil agv.destinationwasreached
		wait loadunloadTIme
		agv.mu.move(A_2)
	else
		A_3.set := True
		agv.destination := A_3_M
		waituntil agv.destinationwasreached
		wait loadunloadTIme
		agv.mu.move(A_3)
	end
	B_2.set := false
	agv.destination := AGVPool
	waituntil agv.destinationwasreached
case "B_3"

	if A_1.set = false
		A_1.set := True
		A := A_1
	elseif A_2.set = false
		A_2.set := True
		A := A_2
	else
		A_3.set := True
		A := A_3
	end

	agv.destination := B_3_M
	waituntil agv.destinationwasreached
	wait loadunloadTIme
	B_3.mu.move(agv)
	if A = A_1
		A_1.set := True
		agv.destination := A_1_M
		waituntil agv.destinationwasreached
		wait loadunloadTIme
		agv.mu.move(A_1)
	elseif A = A_2
		A_2.set := True
		agv.destination := A_2_M
		waituntil agv.destinationwasreached
		wait loadunloadTIme
		agv.mu.move(A_2)
	else
		A_3.set := True
		agv.destination := A_3_M
		waituntil agv.destinationwasreached
		wait loadunloadTIme
		agv.mu.move(A_3)
	end
	B_3.set := false
	agv.destination := AGVPool
	waituntil agv.destinationwasreached
end

agv.isidle := true
  • ์กฐ๊ฑด: AMR์ด ์ž‘์—… ํ›„ ๋ฐ˜๋“œ์‹œ AGVPool๋กœ ๋ณต๊ท€
  • AMR ์†์„ฑ:
    • Capacity: 1
    • HomeLocation: AGVPool
  • ๋Œ€๊ธฐ ๋กœ์ง ๊ณ ๋ ค: AGV๊ฐ€ ๋ณต๊ท€ ์ค‘์ธ ์ƒํ™ฉ์—์„œ ์ƒˆ๋กœ์šด Job์ด ๋Œ€๊ธฐํ•˜๋„๋ก ์„ค๊ณ„

3๏ธโƒฃ ์‹คํ—˜ ๊ณ„ํš๋ฒ• - ExperimentManager

  • ์‹คํ—˜ ๋ชฉ์ : AGV ์ˆ˜์— ๋”ฐ๋ฅธ ์ƒ์‚ฐ์„ฑ๊ณผ ํšจ์œจ์„ฑ ๋น„๊ต
  • ๋ณ€์ˆ˜: AGV ์ˆ˜๋Ÿ‰ (1, 2, 3, 4 ....)
  • ๊ณ ์ • ์กฐ๊ฑด:
    • ๊ณต์ • ์ฒ˜๋ฆฌ์‹œ๊ฐ„ (60์ดˆ)
    • ์‹œ๋ฎฌ๋ ˆ์ด์…˜ ๊ธฐ๊ฐ„ (7์ผ)
    • Source ๊ฐ„๊ฒฉ (Interval Source, ์ˆ˜์น˜ ๊ณ ์ •)
  • ์ธก์ • ํ•ญ๋ชฉ:
    • ์ด ์ƒ์‚ฐ๋Ÿ‰ (Units Per Day)
  • ์‹คํ—˜ ๋ฐฉ์‹:
    • Experiment Manager 
    • ๊ฒฐ๊ณผ๋Š” ํ‘œ ํ˜•ํƒœ๋กœ ๋น„๊ต ๋ถ„์„

๐Ÿ“Š ์‹คํ—˜ ์กฐ๊ฑด ๋ณต์Šต

  • ๊ณต์ • ํ๋ฆ„: Start → B → A → End
  • ๊ณต์ • ์ฒ˜๋ฆฌ์‹œ๊ฐ„:
    • B zone: 60์ดˆ
    • A zone: 60์ดˆ
  • AMR ์„ค์ •:
    • ํšŒ์ „ ๋ฐ˜๊ฒฝ 0m (์ œ์ž๋ฆฌ ํšŒ์ „)
    • ์šฉ๋Ÿ‰ 1, ๋ช…๋ น 1ํšŒ ์ˆ˜ํ–‰ ํ›„ AGVpool ๋ณต๊ท€
  • ๋ชฉํ‘œ: ์ผ์ผ ์ƒ์‚ฐ๋Ÿ‰ 600๊ฐœ ์ด์ƒ
  • ์‹œ๋ฎฌ๋ ˆ์ด์…˜ ๊ธฐ๊ฐ„: 7์ผ

๐Ÿงช ์‹คํ—˜ ๊ฒฐ๊ณผ ์š”์•ฝ

AGV ๋Œ€์ˆ˜ ๋ณ„ ์ผ์ผ ์ƒ์‚ฐ๋Ÿ‰ (UPD)

 

1๋Œ€ 225๊ฐœ ๋ณ‘๋ชฉ ๋ฐœ์ƒ
2๋Œ€ 433๊ฐœ ์ผ๋ถ€ ๊ฐœ์„ 
3๋Œ€ 645๊ฐœ โœ… ๋ชฉํ‘œ ๋‹ฌ์„ฑ
4๋Œ€ 623๊ฐœ โœ… ๋ชฉํ‘œ ๋‹ฌ์„ฑ Idle ์ฆ๊ฐ€, ์ผ๋ถ€ ๋ณ‘๋ชฉ ๋ฐœ์ƒ
5๋Œ€ 728๊ฐœ โœ… ๋ชฉํ‘œ ๋‹ฌ์„ฑ Idle ์ฆ๊ฐ€, ์ผ๋ถ€ ๋ณ‘๋ชฉ ๋ฐœ์ƒ ์ตœ๋Œ€ Capa ๋„๋‹ฌ
 

โ€ป ์‹คํ—˜ ์ˆ˜์น˜๋Š” ์˜ˆ์‹œ์ž…๋‹ˆ๋‹ค. ์‹ค์ œ ๊ฒฐ๊ณผ์— ๋งž๊ฒŒ ์ˆ˜์ •ํ•ด์ฃผ์„ธ์š”.


๐Ÿ” ๋ถ„์„

  • AGV 1๋Œ€์ผ ๋•Œ๋Š” ๋ช…ํ™•ํ•œ ๋ณ‘๋ชฉ์ด ๋ฐœ์ƒํ•˜๋ฉฐ, Waiting Time์ด ๋งค์šฐ ํฝ๋‹ˆ๋‹ค.
  • 2๋Œ€๋กœ ๋Š˜๋ฆฌ๋ฉด ์ƒ์‚ฐ๋Ÿ‰์ด ํฌ๊ฒŒ ์ฆ๊ฐ€ํ•˜์ง€๋งŒ ๋ชฉํ‘œ์น˜์—๋Š” ๋ฏธ๋‹ฌ
  • 3๋Œ€์—์„œ ์ƒ์‚ฐ๋Ÿ‰ 600๊ฐœ ์ด์ƒ ๋‹ฌ์„ฑ, Waiting Time๊ณผ Idle Time๋„ ๊ท ํ˜• ์žกํž˜
  • 4๋Œ€๋กœ ๋Š˜๋ฆฌ๋ฉด ์ƒ์‚ฐ๋Ÿ‰์€ ์†Œํญ ์ฆ๊ฐ€ํ•˜์ง€๋งŒ Idle Time์ด ๊ธ‰์ฆ → ํšจ์œจ ์ €ํ•˜
  • 5๋Œ€๋กœ ๋Š˜๋ฆฌ๋ฉด ํ•ด๋‹น ๋ผ์ธ ์ตœ๋Œ€ ์ƒ์‚ฐ Capa ๋„๋‹ฌ

๐Ÿ“Œ ๊ฒฐ๋ก 

  • ์ตœ์  AGV ์ˆ˜: 3๋Œ€
  • ํˆฌ์ž ๋Œ€๋น„ ์ˆ˜์ต ์ธก๋ฉด์—์„œ, 3๋Œ€๊ฐ€ ์ƒ์‚ฐ์„ฑ๊ณผ ํšจ์œจ์˜ ๊ท ํ˜•์ 
  • AGV๋ฅผ ๋” ๋Š˜๋ฆฌ๋ฉด ์ƒ์‚ฐ๋Ÿ‰์€ ์ •์ฒด๋˜๊ณ  Idle๋งŒ ์ฆ๊ฐ€ → ๊ณผ์ž‰ ํˆฌ์ž
  • ์ตœ๋Œ€ Capa๊ฐ€ ์ค‘์š”ํ•  ๊ฒฝ์šฐ 5๋Œ€ ๋ฐฐ์น˜ ๊ณ ๋ ค
  • ๋‹ค์šด๋กœ๋“œ