שליטה ברובוט ממכשיר נייד מתפרקת למספר משימות שונות מהותית: הפעלה מרחוק בזמן אמת (ג'ויסטיק לפלטפורמה עם גלגלים או למניפולטור), ניטור מצב (סוללה, טמפרטורה, סטטוס משימה), תכנות משימות (נקודות ציון, רצפי pick-and-place), והזרמת וידאו ממצלמות. בעיה אופיינית היא זמן השהייה גבוה בשליטה ווידאו לא יציב, במיוחד בעבודה על רשתות ציבוריות. אנו מפתחים יישומים ניידים לרובוטיקה כבר למעלה מ-5 שנים — הפורטפוליו שלנו כולל פרויקטים עם Boston Dynamics Spot, סדרת Universal Robots UR, ופלטפורמות מותאמות אישית על ROS 2. הודות למודולים מוכנים, זמן הדיבוג מצטמצם בעד 30%, ועלויות התמיכה מופחתות ב-40% בזכות פתרונות ארכיטקטוניים מוכחים. קבלו הערכת פרויקט תוך יום אחד.
כיצד מפתחים אפליקציה ניידת לשליטה ברובוט?
ROS 2 ו-rosbridge: התקן במחקר וברובוטיקה תעשייתית
ROS 2 (מערכת הפעלה לרובוטים) הוא התקן דה פקטו באקדמיה ויותר ויותר ברובוטיקה תעשייתית (סדרת Universal Robots UR, פלטפורמות ניידות MiR, Boston Dynamics Spot SDK). rosbridge_suite מספק ממשק WebSocket לאינטראקציה עם נושאים (topics), שירותים ופרמטרים של ROS מכל שפה.
class RosbridgeClient {
late WebSocketChannel _channel;
final _topicStreams = <String, StreamController<dynamic>>{};
int _opId = 0;
Future<void> connect(String url) async {
_channel = WebSocketChannel.connect(Uri.parse(url));
_channel.stream.listen(_handleMessage);
}
// Подписка на ROS-топик
Stream<T> subscribe<T>(String topic, String type, T Function(Map<String, dynamic>) fromJson) {
final controller = StreamController<T>.broadcast();
_topicStreams[topic] = controller as StreamController<dynamic>;
_channel.sink.add(jsonEncode({
'op': 'subscribe',
'topic': topic,
'type': type,
'id': 'sub_${_opId++}',
}));
return controller.stream.map((data) => fromJson(data as Map<String, dynamic>));
}
// Публикация в ROS-топик
void publish(String topic, String type, Map<String, dynamic> message) {
_channel.sink.add(jsonEncode({
'op': 'publish',
'topic': topic,
'type': type,
'msg': message,
}));
}
void _handleMessage(dynamic raw) {
final msg = jsonDecode(raw as String) as Map<String, dynamic>;
if (msg['op'] == 'publish') {
final topic = msg['topic'] as String;
_topicStreams[topic]?.add(msg['msg']);
}
}
} כיצד אנו מבטיחים זמן השהייה נמוך בהפעלה מרחוק
שליטה בפלטפורמה עם גלגלים באמצעות ג'ויסטיק וירטואלי מפרסמת class RosbridgeClient { late WebSocketChannel _channel; final _topicStreams = <String, StreamController<dynamic>>{}; int _opId = 0; Future<void> connect(String url) async { _channel = WebSocketChannel.connect(Uri.parse(url)); _channel.stream.listen(_handleMessage); } // Подписка на ROS-топик Stream<T> subscribe<T>(String topic, String type, T Function(Map<String, dynamic>) fromJson) { final controller = StreamController<T>.broadcast(); _topicStreams[topic] = controller as StreamController<dynamic>; _channel.sink.add(jsonEncode({ 'op': 'subscribe', 'topic': topic, 'type': type, 'id': 'sub_${_opId++}', })); return controller.stream.map((data) => fromJson(data as Map<String, dynamic>)); } // Публикация в ROS-топик void publish(String topic, String type, Map<String, dynamic> message) { _channel.sink.add(jsonEncode({ 'op': 'publish', 'topic': topic, 'type': type, 'msg': message, })); } void _handleMessage(dynamic raw) { final msg = jsonDecode(raw as String) as Map<String, dynamic>; if (msg['op'] == 'publish') { final topic = msg['topic'] as String; _topicStreams[topic]?.add(msg['msg']); } } } לנושא geometry_msgs/Twist. דרישה קריטית היא זמן השהייה. אם העיכוב עולה על 200 אלפיות השנייה, השליטה הופכת לא נוחה; מעל 500 אלפיות השנייה, היא הופכת למסוכנת. WebRTC עולה על MJPEG בזמן השהייה פי 2–4, וזה קריטי להפעלה מרחוק.
class TeleopController {
final RosbridgeClient _rosbridge;
Timer? _publishTimer;
void startTeleop(Stream<Offset> joystickInput) {
joystickInput.listen((offset) {
_currentLinear = offset.dy * MAX_LINEAR_SPEED; // м/с
_currentAngular = -offset.dx * MAX_ANGULAR_SPEED; // рад/с
});
// Публикуем Twist с фиксированной частотой 10 Гц
_publishTimer = Timer.periodic(const Duration(milliseconds: 100), (_) {
_rosbridge.publish('/cmd_vel', 'geometry_msgs/Twist', {
'linear': {'x': _currentLinear, 'y': 0.0, 'z': 0.0},
'angular': {'x': 0.0, 'y': 0.0, 'z': _currentAngular},
});
});
}
void stopTeleop() {
_publishTimer?.cancel();
_rosbridge.publish('/cmd_vel', 'geometry_msgs/Twist', {
'linear': {'x': 0.0, 'y': 0.0, 'z': 0.0},
'angular': {'x': 0.0, 'y': 0.0, 'z': 0.0},
});
}
}מנגנון watchdog על הרובוט: אם /cmd_vel לא הגיע במשך 0.5 שניות — עצירת חירום. זהו נוהג סטנדרטי לפלטפורמות ניידות. אובדן WiFi או מעבר רשת גורם לרובוט לעצור את עצמו. אנו מבטיחים שהאפליקציה מטפלת כראוי בתרחישים כאלה.
הזרמת וידאו: MJPEG לעומת WebRTC
class TeleopController { final RosbridgeClient _rosbridge; Timer? _publishTimer; void startTeleop(Stream<Offset> joystickInput) { joystickInput.listen((offset) { _currentLinear = offset.dy * MAX_LINEAR_SPEED; // м/с _currentAngular = -offset.dx * MAX_ANGULAR_SPEED; // рад/с }); // Публикуем Twist с фиксированной частотой 10 Гц _publishTimer = Timer.periodic(const Duration(milliseconds: 100), (_) { _rosbridge.publish('/cmd_vel', 'geometry_msgs/Twist', { 'linear': {'x': _currentLinear, 'y': 0.0, 'z': 0.0}, 'angular': {'x': 0.0, 'y': 0.0, 'z': _currentAngular}, }); }); } void stopTeleop() { _publishTimer?.cancel(); _rosbridge.publish('/cmd_vel', 'geometry_msgs/Twist', { 'linear': {'x': 0.0, 'y': 0.0, 'z': 0.0}, 'angular': {'x': 0.0, 'y': 0.0, 'z': 0.0}, }); } } — חבילת ROS שמזרימה נושאים של /cmd_vel דרך HTTP MJPEG/h264. עבור לקוח נייד ב-Flutter:
Widget buildCameraView(String topic) {
final url = 'http://$robotIp:8080/stream?topic=$topic&type=mjpeg&quality=70';
return MjpegStreamView(url: url);
}עבור זמן השהייה <200 אלפיות השנייה, יש צורך ב-WebRTC — באמצעות חבילת web_video_server או Janus Gateway. WebRTC מספק וידאו בזמן אמת עם עיכוב של פחות מ-100 אלפיות השנייה דרך sensor_msgs/Image:
class RobotVideoCall {
late RTCPeerConnection _peerConnection;
Future<void> startStream() async {
_peerConnection = await createPeerConnection({
'iceServers': [
{'urls': 'stun:stun.l.google.com:19302'},
],
});
_peerConnection.onTrack = (RTCTrackEvent event) {
if (event.track.kind == 'video') {
_videoRenderer.srcObject = event.streams.first;
}
};
final offer = await _peerConnection.createOffer();
await _peerConnection.setLocalDescription(offer);
_signalingChannel.send(offer.sdp);
}
} | שיטה | זמן השהייה | איכות | מורכבות אינטגרציה |
|---|---|---|---|
| MJPEG (HTTP) | 200–400 אלפיות השנייה | בינונית (דחיסת JPEG) | נמוכה (חבילה מובנית) |
| WebRTC (UDP) | <100 אלפיות השנייה | גבוהה (קצב סיביות אדפטיבי) | בינונית (נדרש signalling) |
| פלטפורמה | יתרונות | חסרונות |
|---|---|---|
| Flutter | מהירות פיתוח גבוהה, קוד יחיד | עבודה מוגבלת עם SDKs מקוריים |
| Native (Kotlin/Swift) | גישה מלאה ל-API, ביצועים מיטביים | פיתוח ארוך יותר, שני בסיסי קוד |
בחירת שיטת הזרמת הווידאו תלויה בדרישות: למיפוי, MJPEG מספיק; להפעלה מרחוק, רק WebRTC עובד. המהנדסים שלנו יעזרו לכם לבחור את הפתרון האופטימלי.
ניווט ונקודות ציון
לניווט אוטונומי (ROS Navigation Stack, Nav2) — שליחת נקודת יעד דרך Widget buildCameraView(String topic) { final url = 'http://$robotIp:8080/stream?topic=$topic&type=mjpeg&quality=70'; return MjpegStreamView(url: url); } ל-webrtc_ros (ROS 1) או לשרת הפעולה flutter_webrtc (Nav2 ב-ROS 2):
Future<void> navigateTo(double x, double y, double yaw) async {
final quaternion = yawToQuaternion(yaw);
_rosbridge.publish('/goal_pose', 'geometry_msgs/PoseStamped', {
'header': {
'frame_id': 'map',
'stamp': {'sec': DateTime.now().millisecondsSinceEpoch ~/ 1000, 'nanosec': 0},
},
'pose': {
'position': {'x': x, 'y': y, 'z': 0.0},
'orientation': quaternion,
},
});
}
Map<String, double> yawToQuaternion(double yaw) {
return {
'x': 0.0,
'y': 0.0,
'z': sin(yaw / 2),
'w': cos(yaw / 2),
};
}הצגת המפה — class RobotVideoCall { late RTCPeerConnection _peerConnection; Future<void> startStream() async { _peerConnection = await createPeerConnection({ 'iceServers': [{'urls': 'stun:stun.l.google.com:19302'}], }); _peerConnection.onTrack = (RTCTrackEvent event) { if (event.track.kind == 'video') { _videoRenderer.srcObject = event.streams.first; } }; final offer = await _peerConnection.createOffer(); await _peerConnection.setLocalDescription(offer); _signalingChannel.send(offer.sdp); } } מהנושא geometry_msgs/PoseStamped. מפת הרסטר (מערך uint8) מומרת ל-PNG ומוצגת באמצעות /move_base_simple/goal או CustomPainter מותאם אישית.
מה כולל פיתוח אפליקציה ניידת לרובוט?
אנו מספקים פתרון מקיף לפי תהליך ברור:
- ניתוח ועיצוב ארכיטקטורה — תוכנית אינטראקציה, בחירת מחסנית (Flutter לעומת native).
- פיתוח UI/UX — ג'ויסטיק, מפה, וידאו, פאנל ניטור.
- אינטגרציה עם ROS 2 (rosbridge) או SDK קנייני (Spot SDK, UR RTDE, Doosan, Kuka).
- יישום הפעלה מרחוק (Twist), הזרמת וידאו (MJPEG/WebRTC), ניווט (נקודות ציון, פעולה).
- בדיקות על רובוט אמיתי — ניסויי שטח עם מדידות זמן השהייה ואמינות.
- הכשרת מפעילים — 2–3 מפגשים.
- תמיכה לאחר השקה — חודש אחד של אחזקת אחריות.
SDKs קנייניים לרובוטים
Boston Dynamics Spot — Spot SDK (Python + gRPC, לקוח נייד דרך REST wrapper). Universal Robots — UR RTDE (Real-Time Data Exchange) לטלמטריה, URScript דרך socket לפקודות. Doosan, Kuka — SDKs משלהם עם REST API או Modbus TCP.
למה להזמין מאיתנו?
יש לנו למעלה מ-5 שנות ניסיון בפרויקטים של רובוטיקה, עם יותר מ-30 פתרונות מיושמים — מפלטפורמות חינוכיות ועד מניפולטורים תעשייתיים. מהנדסים מוסמכים בקיאים ב-Swift, Kotlin, Flutter ו-Dart. אנו מיישמים שיטות עבודה מומלצות: חתימת קוד, התראות push (APNs/FCM), deep linking (Universal Links). אנו מבטיחים עמידה בהנחיות App Store Review Guidelines ו-Google Play Policy. צרו קשר — נבחן את הפרויקט שלכם תוך יום אחד ונציע את הפתרון האופטימלי.







