如何通过Wi-Fi或蓝牙实现Kotlin与Raspberry Pi 4端Python通信控制机械臂
安卓Kotlin与树莓派Python通信实现机械臂控制方案
两种成熟落地方案可选,优先选Wi-Fi TCP Socket方案,实现简单、延迟低、稳定性好,完全满足机械臂方向控制的需求;蓝牙方案适合无局域网的场景,配置相对繁琐。
方案一:Wi-Fi TCP Socket通信(推荐)
核心逻辑:树莓派作为TCP服务端在固定端口监听,安卓端作为客户端接入同一局域网后主动连接树莓派,通过长连接传输短字符串指令(比如上移传UP、下移传DOWN),解析后直接触发机械臂动作。
树莓派Python端配置
- 前期准备
- 确保树莓派和安卓手机连接同一个Wi-Fi,终端执行
ifconfig wlan0查看树莓派局域网IP(inet字段后的地址,比如192.168.3.42) - 系统防火墙放开你要使用的端口(比如选8888端口,执行
sudo ufw allow 8888即可) - 不需要额外安装第三方库,直接用Python自带的socket库写服务端:
import socket # 导入你自己写的机械臂控制逻辑,比如舵机控制函数 # from arm_driver import move_up, move_down, move_left, move_right LISTEN_IP = '0.0.0.0' # 监听所有网卡请求 LISTEN_PORT = 8888 server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) server.bind((LISTEN_IP, LISTEN_PORT)) server.listen(1) # 仅允许单客户端连接,适配单手机控制场景 print(f"机械臂控制服务已启动,监听端口{LISTEN_PORT}") while True: conn, client_addr = server.accept() print(f"客户端已连接:{client_addr}") try: while True: # 单次最多接收1024字节,足够承载短控制指令 raw_data = conn.recv(1024).decode('utf-8').strip() if not raw_data: break print(f"收到指令:{raw_data}") # 匹配指令执行对应动作 if raw_data == "UP": # move_up() 替换成你自己的机械臂上移逻辑 print("执行上移动作") elif raw_data == "DOWN": # move_down() print("执行下移动作") elif raw_data == "LEFT": # move_left() print("执行左移动作") elif raw_data == "RIGHT": # move_right() print("执行右移动作") # 回执给安卓端,确认指令已执行 conn.sendall("OK".encode('utf-8')) except Exception as e: print(f"连接异常:{str(e)}") finally: conn.close() print("客户端断开,等待重连") - 确保树莓派和安卓手机连接同一个Wi-Fi,终端执行
- 可选优化:给这个Python脚本配置开机自启,不用每次树莓派重启后手动启动服务。
安卓端Kotlin实现
- 权限配置:在
AndroidManifest.xml中添加网络权限,该权限为普通权限,不需要动态申请:
*别在主线程做任何网络读写操作,安卓4.0以上直接禁止主线程网络请求,会抛异常崩溃,用协程切IO线程处理即可。<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> - 封装Socket连接管理类,保持长连接减少每次发指令的连接开销,不要每次点按钮都新建连接:
import java.io.BufferedReader import java.io.BufferedWriter import java.io.InputStreamReader import java.io.OutputStreamWriter import java.net.Socket import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext object ArmControlSocket { private var socket: Socket? = null private var outputWriter: BufferedWriter? = null private var inputReader: BufferedReader? = null // 替换成你自己树莓派的局域网IP和端口 private const val TARGET_IP = "192.168.3.42" private const val TARGET_PORT = 8888 // 进入控制页时调用,建立连接 suspend fun connect(): Boolean = withContext(Dispatchers.IO) { return@withContext try { socket = Socket(TARGET_IP, TARGET_PORT).apply { soTimeout = 5000 // 连接/读写超时设为5秒 } outputWriter = BufferedWriter(OutputStreamWriter(socket!!.getOutputStream())) inputReader = BufferedReader(InputStreamReader(socket!!.getInputStream())) true } catch (e: Exception) { e.printStackTrace() false } } // 按钮点击时调用,发送控制指令 suspend fun sendCmd(command: String): Boolean = withContext(Dispatchers.IO) { return@withContext try { outputWriter?.apply { write(command) newLine() flush() } // 等待树莓派执行完成的回执 val ack = inputReader?.readLine() ack == "OK" } catch (e: Exception) { e.printStackTrace() false } } // 退出控制页时调用,释放连接 fun release() { try { inputReader?.close() outputWriter?.close() socket?.close() } catch (e: Exception) { e.printStackTrace() } finally { socket = null outputWriter = null inputReader = null } } } - 给你已经做好的四个方向按钮绑定点击事件,示例(上移按钮):
binding.btnMoveUp.setOnClickListener { lifecycleScope.launch { val sendSuccess = ArmControlSocket.sendCmd("UP") if (!sendSuccess) { Toast.makeText(this@ControlActivity, "指令发送失败,请检查连接", Toast.LENGTH_SHORT).show() } } } // 其余三个按钮同理,分别传入"DOWN"、"LEFT"、"RIGHT"作为指令参数即可
方案一注意事项
- 记得给树莓派在路由器后台绑定静态IP,不然DHCP动态分配的IP每次树莓派重启都会变,安卓端写死的IP会直接连不上
- 如果长时间不操作连接被路由器自动断开,可以加个简单的心跳逻辑:每隔10秒发个
PING指令,树莓派收到后回PONG,保持连接活跃 - 调试阶段先不要接机械臂,先看树莓派端日志能不能正常收到指令,通信调通了再接硬件动作逻辑,避免误触发
方案二:蓝牙SPP通信(无局域网场景备选)
如果使用场景没有可用Wi-Fi,可以用经典蓝牙的SPP串口协议实现通信,整体逻辑和Socket方案类似,只是传输通道换成蓝牙:
- 树莓派端先安装蓝牙依赖:
sudo apt install pi-bluetooth bluez python3-pybluez,编写蓝牙服务端,使用通用SPP UUID00001101-0000-1000-8000-00805F9B34FB监听连接 - 安卓端添加蓝牙相关权限,安卓12及以上需要动态申请
BLUETOOTH_SCAN、BLUETOOTH_CONNECT权限,先完成和树莓派的蓝牙配对,连接成功后拿到输入输出流,后续发指令的逻辑和Wi-Fi Socket完全一致,直接往输出流写字符串指令即可
*蓝牙方案延迟比Wi-Fi高、有效连接距离短、配对步骤繁琐,有Wi-Fi的情况下优先选前一种方案。
通用调试技巧
- 安卓端连不上的时候,先在手机上用网络调试工具telnet树莓派的IP和端口,先确认网络链路通不通,再查代码逻辑
- 控制指令尽量用短字符串,不要传复杂的JSON或者结构体,降低传输解析出错的概率
- 可以给指令加个简单的校验位,避免信号干扰导致指令传错触发机械臂误动作
内容的提问来源于stack exchange,提问作者Rares
相关产品推荐
相关产品推荐

