[Plant Simulation Study #05] – Xbox ์ปจํŠธ๋กค๋Ÿฌ๋กœ Plant Simulation ์ œ์–ดํ•˜๊ธฐ (Socket ํ†ต์‹  ํ™œ์šฉ)

๐Ÿงช [Plant Simulation Study #05] – Xbox ์ปจํŠธ๋กค๋Ÿฌ๋กœ Plant Simulation ์ œ์–ดํ•˜๊ธฐ (Socket ํ†ต์‹  ํ™œ์šฉ)

๐ŸŽฌ ๊ฐœ์š”

์ด๋ฒˆ ๋ฐ๋ชจ์—์„œ๋Š” Plant Simulation๊ณผ Xbox ๊ฒŒ์ž„ ์ปจํŠธ๋กค๋Ÿฌ๋ฅผ ์—ฐ๋™ํ•ด๋ณด์•˜์Šต๋‹ˆ๋‹ค.
๋ชฉํ‘œ๋Š” ๋‹จ์ˆœํžˆ ์‹œ๋ฎฌ๋ ˆ์ด์…˜์„ ๋ณด๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ, ์™ธ๋ถ€ ์žฅ์น˜๋ฅผ ํ†ตํ•ด ์‹ค์‹œ๊ฐ„์œผ๋กœ ๊ฐ์ฒด๋ฅผ ์ œ์–ดํ•ด๋ณด๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.
์ด๋ฅผ ํ†ตํ•ด ์‚ฌ์šฉ์ž๋Š” ์‹œ๋ฎฌ๋ ˆ์ด์…˜ ๋ชจ๋ธ์„ ๋ณด๋‹ค ์ธํ„ฐ๋ž™ํ‹ฐ๋ธŒํ•˜๊ณ  ๋™์ ์œผ๋กœ ์‹คํ—˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • ์ œ์ž‘ ๋ชฉ์ : ์™ธ๋ถ€ ๋””๋ฐ”์ด์Šค๋ฅผ ํ†ตํ•œ ์‹ค์‹œ๊ฐ„ ์ œ์–ด ํ…Œ์ŠคํŠธ
  • ์‚ฌ์šฉ ๊ธฐ์ˆ : Python + Xbox Controller + Socket ํ†ต์‹  + Plant Simulation
  • ์‚ฌ์šฉ ๊ธฐ๋Šฅ: Plant Simulation์˜ Method + SocketClient ๊ฐ์ฒด ํ™œ์šฉ

https://youtu.be/wE22Czmx6lM

 


๐Ÿ› ๏ธ ์‹œ๋ฎฌ๋ ˆ์ด์…˜ ๊ตฌ์„ฑ ๋ฐ ํ†ต์‹  ๊ตฌ์กฐ

๊ตฌ์„ฑ ์š”์†Œ์„ค๋ช…
์ž…๋ ฅ ์žฅ์น˜ Xbox ์ปจํŠธ๋กค๋Ÿฌ (Python์œผ๋กœ ์ž…๋ ฅ๊ฐ’ ์ˆ˜์‹ )
์ค‘๊ฐ„ ์ฒ˜๋ฆฌ Python์—์„œ ์†Œ์ผ“ ์„œ๋ฒ„ ์šด์˜, ์ขŒ์šฐ/์ƒํ•˜ ๊ฐ’ ์ฒ˜๋ฆฌ
์‹œ๋ฎฌ๋ ˆ์ด์…˜ Plant Simulation์—์„œ SocketClient๋กœ Python ์„œ๋ฒ„์— ์—ฐ๊ฒฐ, ๋ฐ์ดํ„ฐ ์ˆ˜์‹  ํ›„ ๊ฐ์ฒด ์ด๋™
์ œ์–ด ๋Œ€์ƒ MU ๋˜๋Š” 3D ๊ฐ์ฒด์˜ ์œ„์น˜, ์†๋„ ๋“ฑ ์‹ค์‹œ๊ฐ„ ์ œ์–ด ๊ฐ€๋Šฅ
 


๐Ÿ”ง ์ฃผ์š” ๊ตฌํ˜„ ๋ฐฉ์‹

  • Python์—์„œ pygame ๋˜๋Š” inputs ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ํ™œ์šฉํ•˜์—ฌ Xbox ์ปจํŠธ๋กค๋Ÿฌ ๊ฐ’์„ ์ˆ˜์‹ ํ•ฉ๋‹ˆ๋‹ค.
  • ํ•ด๋‹น ๊ฐ’์„ Socket ํ†ต์‹ ์„ ํ†ตํ•ด ๋ฌธ์ž์—ด๋กœ Plant Simulation์— ์ „์†กํ•ฉ๋‹ˆ๋‹ค. server ์ •๋ณด๋ฅผ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค.

  • Plant Simulation์˜ Method์™€ SocketClient ๊ฐ์ฒด๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ•ด๋‹น ๊ฐ’์„ ๋ฐ›์•„ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค.
 
// writes the value to the global variable ’MessageReceived’
if strLen(SocketMessage) = 0
    MessageReceived := to_str(strAscii(SocketMessage)); // byte received
else
    MessageReceived := to_str(SocketMessage); // string received
end

 

  • ์†Œ์ผ“๋ฐ์ดํ„ฐ๋ฅผ ์ด๋™๋ฐ์ดํ„ฐ๋กœ Plant Simulation ๋‚ด์—์„œ ๊ตฌ๋™
-- param attribute: string, oldValue, newValue: string
-- param attribute: string, oldValue: string
param newValue: string

switch newValue
case "UP,1"

	if ํ˜„์žฌ๋กœ๋ด‡ = void or ํ˜„์žฌ_์ œ์–ด์ถ• = ""
		messagebox("๋กœ๋ด‡๊ณผ ์ œ์–ด์ถ•์„ ๋‹ค์‹œ ํ™•์ธํ•ด์ฃผ์„ธ์š”.")
		return
	end

	switch ํ˜„์žฌ_์ œ์–ด์ถ•
	case "J1"
		ํ˜„์žฌ๋กœ๋ด‡.J1 := ํ˜„์žฌ๋กœ๋ด‡.J1 + ์ด๋™๊ฐ’
		var J1_num := ํ˜„์žฌ๋กœ๋ด‡.J1

		ํ˜„์žฌ๋กœ๋ด‡._3D.getobject("J1").moveTo(J1_num)
	case "J2"
		ํ˜„์žฌ๋กœ๋ด‡.J2 := ํ˜„์žฌ๋กœ๋ด‡.J2 + ์ด๋™๊ฐ’
		var J2_num := ํ˜„์žฌ๋กœ๋ด‡.J2
		ํ˜„์žฌ๋กœ๋ด‡._3D.getobject("J1").getobject("J2").moveTo(J2_num)
	case "J3"
		ํ˜„์žฌ๋กœ๋ด‡.J3 := ํ˜„์žฌ๋กœ๋ด‡.J3 + ์ด๋™๊ฐ’
		var J3_num := ํ˜„์žฌ๋กœ๋ด‡.J3
		ํ˜„์žฌ๋กœ๋ด‡._3D.getobject("J1").getobject("J2").getobject("J3").moveTo(J3_num)
	case "J4"
		ํ˜„์žฌ๋กœ๋ด‡.J4 := ํ˜„์žฌ๋กœ๋ด‡.J4 + ์ด๋™๊ฐ’
		var J4_num := ํ˜„์žฌ๋กœ๋ด‡.J4
		ํ˜„์žฌ๋กœ๋ด‡._3D.getobject("J1").getobject("J2").getobject("J3").getobject("J4").moveTo(J4_num)
	case "J5"
		ํ˜„์žฌ๋กœ๋ด‡.J5 := ํ˜„์žฌ๋กœ๋ด‡.J5 + ์ด๋™๊ฐ’
		var J5_num := ํ˜„์žฌ๋กœ๋ด‡.J5
		ํ˜„์žฌ๋กœ๋ด‡._3D.getobject("J1").getobject("J2").getobject("J3").getobject("J4").getobject("J5").moveTo(J5_num)
	case "J6"
		ํ˜„์žฌ๋กœ๋ด‡.J6 := ํ˜„์žฌ๋กœ๋ด‡.J6 + ์ด๋™๊ฐ’
		var J6_num := ํ˜„์žฌ๋กœ๋ด‡.J6
		ํ˜„์žฌ๋กœ๋ด‡._3D.getobject("J1").getobject("J2").getobject("J3").getobject("J4").getobject("J5").getobject("J6").moveTo(J6_num)
	end
case "UP,-1"

	if ํ˜„์žฌ๋กœ๋ด‡ = void or ํ˜„์žฌ_์ œ์–ด์ถ• = ""
		messagebox("๋กœ๋ด‡๊ณผ ์ œ์–ด์ถ•์„ ๋‹ค์‹œ ํ™•์ธํ•ด์ฃผ์„ธ์š”.")
		return
	end

	switch ํ˜„์žฌ_์ œ์–ด์ถ•
	case "J1"
		ํ˜„์žฌ๋กœ๋ด‡.J1 := ํ˜„์žฌ๋กœ๋ด‡.J1 - ์ด๋™๊ฐ’
		var J1_num1 := ํ˜„์žฌ๋กœ๋ด‡.J1
		ํ˜„์žฌ๋กœ๋ด‡._3D.getobject("J1").moveTo(J1_num1)
	case "J2"
		ํ˜„์žฌ๋กœ๋ด‡.J2 := ํ˜„์žฌ๋กœ๋ด‡.J2 - ์ด๋™๊ฐ’
		var J2_num1 := ํ˜„์žฌ๋กœ๋ด‡.J2
		ํ˜„์žฌ๋กœ๋ด‡._3D.getobject("J1").getobject("J2").moveTo(J2_num1)
	case "J3"
		ํ˜„์žฌ๋กœ๋ด‡.J3 := ํ˜„์žฌ๋กœ๋ด‡.J3 - ์ด๋™๊ฐ’
		var J3_num1 := ํ˜„์žฌ๋กœ๋ด‡.J3
		ํ˜„์žฌ๋กœ๋ด‡._3D.getobject("J1").getobject("J2").getobject("J3").moveTo(J3_num1)
	case "J4"
		ํ˜„์žฌ๋กœ๋ด‡.J4 := ํ˜„์žฌ๋กœ๋ด‡.J4 - ์ด๋™๊ฐ’
		var J4_num1 := ํ˜„์žฌ๋กœ๋ด‡.J4
		ํ˜„์žฌ๋กœ๋ด‡._3D.getobject("J1").getobject("J2").getobject("J3").getobject("J4").moveTo(J4_num1)
	case "J5"
		ํ˜„์žฌ๋กœ๋ด‡.J5 := ํ˜„์žฌ๋กœ๋ด‡.J5 - ์ด๋™๊ฐ’
		var J5_num1 := ํ˜„์žฌ๋กœ๋ด‡.J5
		ํ˜„์žฌ๋กœ๋ด‡._3D.getobject("J1").getobject("J2").getobject("J3").getobject("J4").getobject("J5").moveTo(J5_num1)
	case "J6"
		ํ˜„์žฌ๋กœ๋ด‡.J6 := ํ˜„์žฌ๋กœ๋ด‡.J6 - ์ด๋™๊ฐ’
		var J6_num1 := ํ˜„์žฌ๋กœ๋ด‡.J6
		ํ˜„์žฌ๋กœ๋ด‡._3D.getobject("J1").getobject("J2").getobject("J3").getobject("J4").getobject("J5").getobject("J6").moveTo(J6_num1)
	end

case "A,1"
	if ํ˜„์žฌ๋กœ๋ด‡.empty = false
	else
		pick.mu.move(ํ˜„์žฌ๋กœ๋ด‡)
	end

case "B,1"
	if ํ˜„์žฌ๋กœ๋ด‡.empty = true
		else
		ํ˜„์žฌ๋กœ๋ด‡.mu.move(place)
	end
case "X,1"
	switch ์ด๋™๊ฐ’
	case 1
		์ด๋™๊ฐ’ := 2
	case 2
		์ด๋™๊ฐ’ := 3
	case 3
		์ด๋™๊ฐ’ := 5
	case 5
		์ด๋™๊ฐ’ := 10
	case 10
		์ด๋™๊ฐ’ := 30
	case 30
		์ด๋™๊ฐ’ := 90
	case 90
		์ด๋™๊ฐ’ := 1
	end
case "Y,1"
	switch ํ˜„์žฌ_์ œ์–ด์ถ•
	case ""
		ํ˜„์žฌ_์ œ์–ด์ถ• := "J1"
	case "J1"
		ํ˜„์žฌ_์ œ์–ด์ถ• := "J2"
	case "J2"
		ํ˜„์žฌ_์ œ์–ด์ถ• := "J3"
	case "J3"
		ํ˜„์žฌ_์ œ์–ด์ถ• := "J4"
	case "J4"
		ํ˜„์žฌ_์ œ์–ด์ถ• := "J5"
	case "J5"
		ํ˜„์žฌ_์ œ์–ด์ถ• := "J6"
	case "J6"
		ํ˜„์žฌ_์ œ์–ด์ถ• := "J1"
	end
end

๐Ÿ“ˆ ์‹คํ—˜ ๊ฒฐ๊ณผ ๋ฐ ํ™œ์šฉ ๊ฐ€๋Šฅ์„ฑ

์ด ํ”„๋กœ์ ํŠธ๋Š” ๋‹จ์ˆœํ•œ ๋ฐ๋ชจ ์ด์ƒ์˜ ์˜๋ฏธ๋ฅผ ๊ฐ€์ง‘๋‹ˆ๋‹ค.

  • ์‹ค์ œ ์žฅ๋น„๋‚˜ ๋ฌผ๋ฅ˜ ์žฅ์น˜์™€ ์—ฐ๋™ํ•œ ์‹œ๋ฎฌ๋ ˆ์ด์…˜ ํ…Œ์ŠคํŠธ
  • ๊ฐ€์ƒ ์‹œ์šด์ „(Virtual Commissioning)
  • ๊ต์œก์šฉ ์ธํ„ฐ๋ž™ํ‹ฐ๋ธŒ ๋ชจ๋ธ ์ œ์ž‘ ๋“ฑ ๋‹ค์–‘ํ•œ ํ™œ์šฉ์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

๐Ÿง  ๋งˆ๋ฌด๋ฆฌํ•˜๋ฉฐ

Xbox ์ปจํŠธ๋กค๋Ÿฌ๋Š” ํ•˜๋‚˜์˜ ์˜ˆ์‹œ์ผ ๋ฟ, ์ด ๊ตฌ์กฐ๋ฅผ ์ด์šฉํ•˜๋ฉด ์„ผ์„œ, ๋ชจ๋ฐ”์ผ ์•ฑ, ํ‚ค๋ณด๋“œ, ์ œ์–ด๊ธฐ ๋“ฑ ๋‹ค์–‘ํ•œ ์™ธ๋ถ€ ์ž…๋ ฅ๊ณผ ์—ฐ๋™์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.
Plant Simulation์„ ๋‹จ์ˆœ ๋ถ„์„ ํˆด์ด ์•„๋‹ˆ๋ผ ์‹ค์‹œ๊ฐ„ ์‹คํ—˜๊ณผ ํ”ผ๋“œ๋ฐฑ์ด ๊ฐ€๋Šฅํ•œ ์‹œ๋ฎฌ๋ ˆ์ด์…˜ ํ”Œ๋žซํผ์œผ๋กœ ํ™•์žฅํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ๋ณด์—ฌ์ค€ ์‚ฌ๋ก€์ž…๋‹ˆ๋‹ค.
์•ž์œผ๋กœ ๋” ๋‹ค์–‘ํ•œ ์™ธ๋ถ€ ์ธํ„ฐํŽ˜์ด์Šค์™€ ์—ฐ๊ฒฐํ•ด๋ณด๊ณ ์ž ํ•ฉ๋‹ˆ๋‹ค.