在工业自动化领域,实现手机 APP 与 Modbus-TCP 协议的 PLC 之间的高效通信,能够极大地提升工业控制的便捷性与灵活性。本文将详细介绍如何借助 Modbus4Android 库,在特定开发环境下完成这一功能的实现。
一、开发环境搭建
本次开发选用的是 Android Studio 3.0.0,其安装包为 android-studio-ide-171.4408382-windows.exe。在安装过程中,需按照向导逐步进行操作,注意选择合适的安装路径以及配置相关环境变量。安装完成后,启动 Android Studio,它将为我们提供一个集成开发环境,方便进行 APP 的代码编写、调试等工作。
Java 环境采用的是 java version "1.8.0_181",安装包为 jdk-8u181-windows-x64.exe。安装 Java Development Kit(JDK)时,同样要留意安装路径的选择。安装完成后,需配置系统的环境变量,将 JDK 的安装路径添加到 Path 变量中,确保系统能够正确识别 Java 命令。这一步至关重要,因为 Android 开发依赖于 Java 环境,只有配置正确,Android Studio 才能正常运行并进行 Java 代码的编译和执行。
二、添加 Modbus4Android 库依赖
在 Android Studio 中创建项目后,需要引入 Modbus4Android 库,以便实现与 Modbus-TCP 设备的通信功能。打开项目的build.gradle
文件,在dependencies
闭包中添加implementation 'com.zgkxzx:modbus4And:1.0.0'
(具体版本号可根据实际情况调整)。添加完成后,点击 Android Studio 界面上的 “Sync Now” 按钮,让项目同步依赖库。这一过程中,Gradle 会自动下载 Modbus4Android 库及其相关依赖,并将它们添加到项目中,使我们能够在代码中使用该库提供的功能。
三、APP 功能实现
(一)界面设计
APP 的界面设计参考activity_main.xml
文件,整体采用LinearLayout
线性布局,且垂直排列。
- 标题栏:使用
TextView
组件显示 “ModbusTcp 调试小工具 V1.0”,用于明确应用的名称和用途,让用户一眼就能了解该 APP 的功能范畴。 - 数据显示区:通过多个
TextView
分别展示机器人的各种关键状态数据,包括当前位置、电机速度、电池电量、电池电流、电机 1 故障码以及电机 2 故障码等。这些TextView
的布局和样式经过精心设计,以便清晰、直观地呈现数据,方便用户实时获取设备的运行状态信息。 - 功能按钮区:包含 “位置校准”“行走到此”“前进”“停止”“后退”“返航充电” 等多个按钮。每个按钮都对应着特定的控制指令,用户点击这些按钮,即可向 PLC 发送相应的控制信号,实现对机器人的远程操作。按钮的设计注重用户体验,具有明显的视觉区分度,便于用户快速识别和操作。
- 速度调节区:利用
SeekBar
组件实现速度调节功能。用户可以通过滑动SeekBar
来改变机器人的运行速度,这种交互方式简单直观,符合用户的操作习惯。SeekBar
的进度值与机器人速度之间存在特定的映射关系,通过代码实现这种映射,从而实现对机器人速度的精确控制。 - 日志显示区:使用
TextView
展示 APP 与 PLC 的通信日志。该区域记录了连接状态、操作结果等重要信息,方便开发者在调试过程中查看通信过程中的各种情况,及时发现并解决可能出现的问题。同时,日志显示区的设置也有助于用户了解 APP 的操作历史和设备的响应情况。
(二)功能逻辑实现
- 初始化 Modbus 连接:在
MainActivity
的onCreate
方法中调用modbusInit
方法来初始化 Modbus 连接。
收起
java
private void modbusInit() {
ModbusReq.getInstance().setParam(new ModbusParam()
.setHost("192.168.0.19")
.setPort(502)
.setEncapsulated(false)
.setKeepAlive(true)
.setTimeout(2000)
.setRetries(0))
.init(new OnRequestBack<String>() {
@Override
public void onSuccess(String s) {
Log.d(TAG, "onSuccess " + s);
tvRunLogs.setTextColor(Color.GREEN);
tvRunLogs.setText("连接PLC成功!ModbusTcp服务器IP地址192.168.0.19,端口502");
tvRunLogs.requestLayout();
mb_connected = true;
}
@Override
public void onFailed(String msg) {
Log.d(TAG, "onFailed " + msg);
tvRunLogs.setTextColor(Color.RED);
tvRunLogs.setText("连接192.168.0.19:502失败!请确保手机WIFI已连接到机器人调试网络环境!");
mb_connected = false;
}
});
}
在上述代码中,首先创建ModbusParam
对象,通过该对象配置连接 PLC 所需的各项参数,如 PLC 的 IP 地址("192.168.0.19")、端口号(502)、是否封装(false)、心跳设置(开启)、超时时间(2000 毫秒)以及重试次数(0 次)。然后调用init
方法进行连接初始化,并通过OnRequestBack
回调接口处理连接结果。连接成功时,在日志显示区用绿色字体显示成功信息,并设置连接成功标志位mb_connected
为true
;连接失败时,则用红色字体显示错误信息,并将mb_connected
设置为false
。
2. 定时读取寄存器数据:借助Handler
和Runnable
实现定时任务,每隔 500 毫秒读取一次 PLC 的保持寄存器数据。
收起
java
private void readHoldingRegistersPeriodically() {
ModbusReq.getInstance().readHoldingRegisters(new OnRequestBack<short[]>() {
@Override
public void onSuccess(short[] data) {
Log.d(TAG, "定时读取寄存器数据成功: " + Arrays.toString(data));
int originalInt = ((data[1] & 0xFFFF) << 16) | (data[2] & 0xFFFF);
m_position = (float) originalInt;
m_batt_soc = data[10];
m_batt_curr = (float)((short)data[12]) / 10; //电池电量
m_speed_actual = (float)((short)data[29])*0.30f /3000; //电机速度
// 其他数据解析...
updateTextViews();
if (++m_heatbeat_count > 10) ///心跳下发
{
m_heatbeat_count = 0;
WriteHeartbeat();
}
}
@Override
public void onFailed(String msg) {
Log.e(TAG, "定时读取寄存器数据失败: " + msg);
mb_connected = false;
tvRunLogs.setTextColor(Color.RED);
tvRunLogs.setText("连接已断开!请确保手机WIFI已连接到机器人调试网络环境!");
}
}, 1, 1000, 40);
}
在readHoldingRegistersPeriodically
方法中,调用ModbusReq.getInstance().readHoldingRegisters
方法读取从地址 1000 开始的 40 个保持寄存器数据。读取成功后,根据寄存器数据的定义和协议规范,解析出当前位置、电池电量、电机速度等关键信息,并更新相应的成员变量。接着调用updateTextViews
方法,将解析后的数据更新到界面上的TextView
组件中,实现数据的实时显示。同时,在代码中还设置了心跳机制,当心跳计数m_heatbeat_count
超过 10 时,将其重置为 0 并发送心跳包,以维持与 PLC 的稳定连接。若读取数据失败,记录错误日志,将连接状态标志位mb_connected
设置为false
,并在日志显示区用红色字体提示用户连接已断开,要求用户检查网络连接。
3. 写入寄存器控制机器人运动:以 “前进” 按钮的点击事件处理方法MoveFrontClickEvent
为例,展示如何通过写入寄存器来控制机器人运动。
收起
java
public void MoveFrontClickEvent(View view) {
ModbusReq.getInstance().writeRegisters(new OnRequestBack<String>() {
@Override
public void onSuccess(String s) {
Log.e(TAG, "MoveFront onSuccess " + s);
tvRunLogs.setTextColor(Color.GREEN);
tvRunLogs.setText("前进命令写入成功!");
}
@Override
public void onFailed(String msg) {
Log.e(TAG, "MoveFront onFailed " + msg);
tvRunLogs.setTextColor(Color.RED);
tvRunLogs.setText("前进命令写入失败!");
}
}, 1, 1101, new short[]{(short)((-3000)*seekBarProgress/100), 3, 0,0});
}
在该方法中,根据SeekBar
的当前进度值seekBarProgress
计算出机器人的前进速度,按照协议规定,将速度值以及相关命令字等信息封装成short
数组。然后调用ModbusReq.getInstance().writeRegisters
方法,向 PLC 的地址 1101 写入这些数据。当写入操作成功时,在日志显示区用绿色字体显示 “前进命令写入成功!”;若写入失败,则用红色字体显示错误信息,方便用户和开发者了解操作结果。类似地,“后退”“停止” 等其他控制按钮的功能实现原理与之相似,只是写入的速度值和命令字根据不同的操作需求进行相应调整。
4. 位置校准和行走到此功能:这两个功能通过弹出AlertDialog
对话框,获取用户输入的位置值,并在用户确认后进行相应的寄存器写入操作。
收起
java
public void locationCalibrationClickEvent(View view) {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("位置校准(单位mm)");
final EditText input = new EditText(this);
builder.setView(input);
builder.setPositiveButton("确认", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
String inputText = input.getText().toString();
try {
int position = Integer.parseInt(inputText);
short[] values = new short[]{(short) (position >> 16),(short) position };
ModbusReq.getInstance().writeRegisters(new OnRequestBack<String>() {
@Override
public void onSucc