SEV case study
1. Mô tả bài toán
Sơ đồ mô phỏng nhà máy SEV như hình bên dưới
AMR sẽ xuất phát tại điểm STANDBY 1, chờ nhận nhiệm vụ từ server.
Với mỗi nhiệm vụ, server sẽ gửi danh sách dữ liệu bao gồm bufferId
: chỉ định danh của buffer để lấy hàng (UNLOAD) và lineId
chỉ định danh của Line trả hàng (LOAD).
Vị trí các LINE trả hàng được ký hiệu là : Lxx_1, Lxx_2 trên bản đồ. Trong đó xx là id của line, hậu tố 1, 2 tương ứng với slot 1, 2 của line
Vị trí các buffer lấy hàng được ký hiệu là: Bxx_1, Bxx_2 trên bản đồ. Trong đó xx là id của buffer, hậu tố 1, 2 tương ứng với slot 1, 2 của buffer
Sau khi nhận nhiệm vụ, robot đi 1 vòng. Xuất phát từ STANDBY đi tới khu vực lấy hàng, b ắt đầu bằng điểm B_IN1
. Từ B_IN1
, robot đi chậm để tiếp cận Bxx_1. Robot giảm tốc độ để tiếp cận các băng tải của Bxx_1 cho chính xác. Sau khi lấy hàng xong, robot tiếp tục đi tới điểm lấy hàng (Bxx_2) tiếp theo. Khi đã lấy hàng xong, robot sẽ đi chậm tới điểm B_Out1
để ra khỏi khu vực Buffer.
Sau khi ra khỏi khu vực Buffer, robot sẽ kiểm tra mức pin hiện tại, nếu pin còn thấp thì sẽ di chuyển vào khu vực thay pin.
Sau đó robot đi tới điểm LINE_IN, để vào khu vực trả hàng.
Khu vực trả hàng chia làm 2 khu, các line từ 1 tới 4 sẽ nằm ở 1 khu như trên bản đồ, các line từ 5 đến 8 sẽ nằm ở 1 khu khác.
Tại khu vực các line từ 1 tới 4. Các vị trí ghép băng chuyển để trả hàng (DLxx_1, DLxx_2) nằm trên đường đi chính. Robot sẽ từ LINE_IN rẽ phải tại điểm L04 và đi vào 1 trong những line này. Sau khi xong nhiệm vụ, robot sẽ đi thẳng ra điểm L01_Out và về Standby
Tại khu vực các line từ 5 đến 8. Vị trí ghép băng chuyền để trả hàng (DLxx_1, DLxx_2) sẽ nằm sau bên trong, nên để ghép vào các băng chuyền, robot phải di chuyển tới các điểm đầu line (Lxx_1, Lxx_2) và rẽ phải để đi chậm ghép vào các bằng chuyền (DLxx_1, DLxx_2). Sau khi xong nhiệm vụ, robot sẽ di chuyển ra điểm LO_016 để về STANDBY
2. Soạn TVC-NAV Mission
a. Phần buffer lấy hàng
Quy trinh di chuyển của robot tại buffer:
- Từ vị trí STANDBY, robot di chuyển tới điểm đầu hàng buffer
B_IN
- Từ
B_IN
robot di chuyển chậm để tiếp cận chính xác vào vị trí Buffer Bxx_1. Sau đó lấy hàng từ buffer. - Từ
Bxx_1
, robot di chuyển tới Bxx_2 và lấy hàng. Sau đó di chuyển tới điểm B_Out.
Phần mission tương ứng với quy trình này như sau.
-
Thêm runtime-variable tương ứng với markerId đánh dấu vị trí của Bxx_1 và Bxx_2. Biến
bufferMarkerId
dùng để cập nhật marker id tương ứng vớiBxx_1
, biếnbufferMarkerId2
dùng để cập nhật marker id tương ứng với Bxx_2 -
Các action và thứ tự action trong quy trình này:
-
Robot bắt đầu thực hiện nhiệm vụ từ vị trí STANDBY, nên action đầu tiên, Robot di chuyển từ
STANDBY
tớiB_IN
: Action Follow PathGo to B_In
-
Sau đó robot di chuyển từ
B_IN
tới buffer đầu tiềnBxx_1
: action Follow PathtSTLBuffer1
tham số cho phần này như sau:- Trong phần tham số
webhook host
, là URL gọi tới API thực hiện nhiệm vụ khi robot tới điểmBxx_1
. Ngay sau action Follow Path là action pause để cho robot dừng chờ cho tới khi thực hiện lấy hàng xong. Sau khi thực hiện lấy hàng xong, robot sẽ gọi tới API để resume (unpaused)
- Trong phần tham số
-
Tương tự như trên, robot thực hiên lấy hàng ở
Bxx_2
, bao gôm action Follow PathSTLBuffer2
vàPause
tham số cho phần này: -
Sau khi lấy hàng xong ở
Bxx_2
, robot di chuyển ra điểm B_Out để ra khỏi khu vực Buffer: ActionSTL B_Out
b. Phần kiểm tra mức pin và thay pin
Quy trình cho phần này:
- Sau ra khỏi khu vực Buffer, robot di chuyển từ vị trí
B_Out
tới vị tríOBS_IN
. Tại vị trí này robot gọi API để kiểm tra mức pin. - Nếu mức pin thấp (vd. dưới 30%) robot sẽ di chuyển vào vị trí
BAT
để thay pin, sau đó tiếp tục nhiệm vụ đi tới vị tríLINE_IN
Chi tiết soạn các action cho phần này:
-
Đầu tiên, ta thêm vào 1 runtime-variables để cập nhật mức pin:
batteryLevel
-
Thêm action Follow Path
Go to Collision
, trong action này, trong phần Webhook Callback, ta gọi tới API để cập nhật mức pin vào biếnbatteryLevel
, Đi liền sau action Follow Path là 1 actionPAUSE
để chờ API cập nhật biến: -
Action tiếp theo là Action điều kiện, nếu mức pin thấp, sẽ thực hiện các action để đi thay pin, nếu không robot sẽ đi thẳng tới vị trí
LINE_IN
. tại phần cài đặt điều kiện, kiếm tra biếnbatteryLevel
:- Trong phần điều kiện đúng (mức pin thấp): Ta thêm vào action Follow Path
Go to change Battery
, tại đây action sẽ điều khiển robot đi tới vị tríBAT
để thay pin. Ngay sau đó là actionPAUSE
để chờ robot thay pin. Ngay sau action thay pin là action Follow PathGo to Line_IN
.
- Trong phần điều kiện đúng (mức pin thấp): Ta thêm vào action Follow Path
- Trong phần điều kiện sai (mức pin đủ dùng): Thêm action Follow Path tới vị trí
LINE_IN
c. Phần đi vào line để trả hàng.
Quy trình của phần này:
- Như đã thấy trên bản đồ, phần các line nhận hàng được chia thành 2 khu vực được bố trí khác nhau:
- Mỗi line sẽ có 2 băng chuyền nhận hàng (trừ line số 1), vị trí ghép các bằng chuyền được ký hiệu là
Lxx_1
vàLxx_2
. - Từ line số 1 tới số 4: các băng chuyền trả hàng của các line được bố trí xếp thành hàng liên tiếp, nên robot trả hàng tại các line này sẽ trả hàng ngay trên đường đi chính.
- Từ line số 5 tới line số 8: vị trí các băng chuyền không được bố trí trên đường đi chính mà phải rẽ nhánh đi vào. Sau khi robot trả hàng xong sẽ đi lùi ra và trở lại đường chính.
- Sau khi robot trả hàng xong, robot sẽ đi tiếp trên đường đi chính tới vị trí
Line Out
, cụ thể là vị tríLO_01
với các line từ 1 tới 4, và vị tríLO_0162
với các line từ 5 tới 8. Riêng tại vị trí bằng chuyềnL08_2
, sau khi trả hàng xong robot không đi lùi lại mà đi tiến thẳng tới vị tríLO_016
.
- Mỗi line sẽ có 2 băng chuyền nhận hàng (trừ line số 1), vị trí ghép các bằng chuyền được ký hiệu là
Chi tiết soạn mission cho quy trình này:
-
Quy trình vào line trả hàng sử dụng các runtime-variables sau đây:
lineId
: id của line trả hànglineMarkerId
: marker id đánh dấu vị trí đầu line Lxx_1lineMarkerId2
: marker id đánh dấu vị trí đầu line Lxx_2DLMarkerId
: marker đánh dấu vị trí ghép băng chuyền số 1DLMarkerId2
: marker đánh dấu vị trí ghép bằng chuyền số 2
-
C ác actions cho quy trình này:
-
Thêm action điều kiện, kiểm tra xem line thuộc nhóm <=4 hay >4: chi tiết tham số:
-
Nếu line thuộc nhóm từ 1 tới 4, robot sẽ thực hiên các action sau đấy:
-
4.1. Action Follow Path từ marker
LINE_IN
tới markerL04
. -
4.2. Action Follow Path đi từ marker
L04
tới điểm đầu lineLxx_1
: -
4.3 Action điều kiện kiểm tra line 1 hay không:
-
4.3.1 Nếu là line 1, thì sẽ gọi tới action Follow Path
Go to DL1
, ở mode đi chính xac, sau khi tới điểm đích, sẽ gọi callback trả hàng ở cả 2 băng chuyền. Đồng thời, trong phần callback của action sẽ gọi tới API để trả hàng ở cả 2 băng chuyền. -
4.3.2 Sau action trên là action Follow Path, đi tới điểm Line out
L01_Out
-
4.3.3 Nếu không phải line 1 (line 2-4), thì robot sẽ trả hàng tại 2 bằng chuyền. Danh sách action sẽ bao gồm
-
4.3.4 Action Follow Path
Go to DL1
, điều khiển robot đi châm tiếp cận chính xác vị trí ghép bằng chuyền số 1DLxx_1
. Xong action này, sẽ gọi tới callback để trả hàng và tiếp tục nhiệm vụ sau khi xong (unpause). -
4.3.5 Action Follow Path
Go to DL2
, điều khiển robot đi chậm tiếp cận chính xác vị trí ghép băng chuyền số 2DLxx_2
. Xong action này, sẽ gọi tới callback đê trả hàng vào băng chuyền số 2 và tiếp tục mission. -
4.3.6 Action Follow Path
Go to Line Out
. Robot di chuyển tới điểm ngoài khu vực trả hàngL01_Out
. -
Sau khi robot tới điểm
L01_Out
, thực hiện action Follow PathGo to Standby
.
-
-
-
Nếu line thuộc nhóm từ 5 tới 8, robot sẽ thực hiện các action sau đây:
_ 5.1 Đi tới điểm đầu vào
Lxx_1
, action Follow PathGo to Line slot 1
_ 5.2 Rẽ phải di chuyển vào điểm ghép băng chuyền
DLxx_1
, action Follow PathSTL to DL1
, tham số của action như dưới đây:_ 5.3 Lùi di chuyển trờ lại đường đi chính
Lxx_1
, action Follow PathSTL DL1 to Line 1
, tham số như dưới đây:_ 5.4 Di chuyển sang đầu line
Lxx_2
. action Follow PathGo to Line Slot 2
,_ 5.5 Rẽ phải di chuyển vào điểm ghép băng chuyền
DLxx_2
, action Follow PathSTL to DL2
, tham số của action như dưới đây:_ 5.6 Tại thời điểm này, nếu là line 8 thì robot thì đi thẳng ra điểm LINE_OUT, nếu không thì robot sẽ lùi quay trở lại đường chính. Do đó, action điều kiện
Check Line 8
-
Nếu là line 8, thực hiện action Follow Path ra điểm
LINE_OUT
-
Nếu không phải line 8, Lùi di chuyển trờ lại đường đi chính
Lxx_1
, action Follow PathSTL DL2 to Line 2
. Sau đó di chuyển ra điểmLINE_OUT
-
Di chuyển từ điểm
LINE_OUT
quay trở lại vị tríSTANDBY
-
3. Code ACS Client
- Ở bước trên, ta đã soạn ra một khuôn mẫu mission cho TVC-NAV. Tuy nhiên để TVC-NAV mission hoạt động được thì ta cần có 1 module gửi dữ liệu (tùy theo từng nhiệm vụ) cho TVC-NAV thông qua các runtime-variables đã định nghĩa bên trên.
- Dưới đây là pseudo-code (javascript) mô tả cách viết 1 module điểu khiển hoạt động của TVC-NAV mission đã soạn ở trên với dữ liệu nhận từ ACS.
1. Xử lý dữ liệu nhận từ ACS
- Ở bước này Client nhận bản tin bufferId nhận hàng và lineId trả hàng từ ACS.
- Từ dữ liệu trên, client cần tìm ra markerId của các điểm cần dừng để gửi vào mission.
const MISSION_ID = "7c0a7c7f-75ad-4536-8825-7555595cbd16";
function sevBufferIdToMarkerName(bufferId) {
// chuyển đổi từ bufferId sang tên marker
return {
bufferMarkerId: `B${String(bufferId).padStart(2, "0")}_1`,
bufferMarkerId2: `B${String(bufferId).padStart(2, "0")}_2`,
};
}
function sevLineIdToMarkerName(lineId) {
// chuyển đổi từ lineID sang tên của line marker, vị trí ghép băng chuyền
return {
lineMarkerId: `L${String(lineId).padStart(2, "0")}_1`,
DLMarkerId: `DL${String(lineId).padStart(2, "0")}_1`,
lineMarkerId2: `L${String(lineId).padStart(2, "0")}_2`,
DLMarkerId2: `DL${String(lineId).padStart(2, "0")}_2`,
};
}
let executedMission;
async function prepareVariables(bufferId, lineId) {
// lấy ra danh sách tên các marker dùng trong mission
const bufferMarkerNames = sevBufferIdToMarkerName(bufferId);
const lineMarkerNames = sevLineIdToMarkerName(lineId);
// const listMarkerNames = bufferMarkerNames.concat(lineMarkerNames);
const initialVariables = Object.assign(
{},
bufferMarkerNames,
lineMarkerNames,
);
const mapId = await webappAPI.getActiveMapId();
if (mapId === undefined) {
utils.log("Lỗi gọi nhiệm vụ vì chưa kích hoạt map.");
return;
}
const markers = await webappAPI.getMarkers(mapId);
if (markers === undefined) {
utils.log("Lỗi gọi nhiệm vụ vì không lấy được markers.");
return;
}
// lưu ra danh sách gôm tên và id của các marker
Object.keys(initialVariables).forEach((varName) => {
const markerName = initialVariables[varName];
initialVariables[varName] = webappAPI.getMarkerIdByName(
markers,
markerName,
);
});
// add lineId
initialVariables.lineId = lineId;
return initialVariables;
}
2. Code gọi thực hiện Start Mission
- Do TVC-NAV Mission khi chạy sẽ cần tới dữ liệu để chạy tới line lấy hàng đầu tiên, nên khi gọi API start mission cho TVC-NAV, ta cần gửi cùng với dữ liệu của line đầu tiên
startMission: async (bufferId, lineId) => {
// set initialVariable
const initialVariable = await prepareVariables(bufferId, lineId);
const initialVariables = Object.keys(initialVariable).map((key) => ({key, value: initialVariable[key]}));
// console.log("execute mission: e", params);
executedMission = (await webappAPI.executeMission(MISSION_ID, { initialVariables}))?.data;
console.log("execute mission: ", executedMission);
},
3. Code callback kiểm tra mức pin
router.post("/check-battery", async (req, res) => {
await sevProcess.handleCheckBattery(res);
});
handleCheckBattery: async(res) => {
const batteryLevel = getBatteryLevel();
// set battery Variablese
await webappAPI.setRuntimeVariable(executedMission.id, "batteryLevel", batteryLevel);
// unpaused
res.sendStatus(200);
setTimeout(rosService.unpause, 1000);
},
4. Code callback lấy hàng
router.post("/handle-sev-unload", async (req, res) => {
await sevProcess.handleUnload(res);
});
handleUnload: async (res) => {
unLoad();
// unpaused
res.sendStatus(200);
setTimeout(rosService.unpause, 1000);
},
4. Code callback trả hàng
router.post("/handle-sev-load-both", (req, res) => {
sevProcess.handleLoadBoth(res);
});
handleLoadBoth: (res) => {
loadBoth();
// unpaused
res.sendStatus(200);
setTimeout(rosService.unpause, 1000);
},