履带式机械臂小车的制作分享

1. 运动功能说明

       履带式机械臂小车样机是一款搭载了机械臂的平行履带小车。它的底盘具备基本的行驶和原地转向功能,机械臂具备抬升、放下、抓取等功能。整体上可以实现抓取、搬运、码放等功能,可作为搬运机器人、排爆机器人等的模型使用。

2. 结构说明

      履带式机械臂小车样机的底盘是一个小型平行履带底盘,机械臂包含2个串联的关节模组
和1个舵机夹爪模组。

​ 

​ 

​ 

3. 运动功能实现

     本样机的运动功能相当于是把底盘、关节、夹爪的动作进行组合实现。

3.1 电子硬件

在这个示例中,采用了以下硬件,请大家参考:

Basra主控板(基于Arduino开源方案设计的一款开发板)、Bigfish扩展板7.4V锂电池

3.2 编写程序

编程环境:Arduino 1.8.19

编写并烧录以下代码(Servo_Sync_Se.ino):

/*------------------------------------------------------------------------------------

  版权说明:Copyright 2022 Robottime(Beijing) Technology Co., Ltd. All Rights Reserved.

           Distributed under MIT license.See file LICENSE for detail or copy at

           https://opensource.org/licenses/MIT

           by 机器谱 2022-9-14 https://www.robotway.com/

  ------------------------------

  实验功能: 小车前进→机械臂下落→夹爪闭合→机械臂抬起→小车后退→夹爪张开

  -----------------------------------------------------

  实验接线:

机械爪:D4

腕部(连接机械爪)舵机:D7

底部舵机:D11

左轮:D9,D10

右轮:D5,D6。                                     

------------------------------------------------------------------------------------*/

#include <Servo.h>

int SERVO_SPEED=20;                                        //定义舵机转动快慢的时间

int ACTION_DELAY=200;                                      //定义所有舵机每个状态时间间隔

Servo myServo[6];

int f = 50;                                                     //定义舵机每个状态间转动的次数,以此来确定每个舵机每次转动的角度

int servo_port[6] = {4,7,11,3,8,12};                            //定义舵机引脚

int servo_num = sizeof(servo_port) / sizeof(servo_port[0]);     //定义舵机数量

float value_init[6] = {125, 130, 160, 30, 60, 120};                //定义舵机初始角度

void setup() {

  Serial.begin(9600);

  pinMode(5, OUTPUT);

  pinMode(6, OUTPUT);

  pinMode(9, OUTPUT);

  pinMode(10, OUTPUT);

  for(int i=0;i<servo_num;i++){

    ServoGo(i,value_init[i]);

  }

}

void loop() {

  /*

  servo_move(90, 130, 15, 70, 10, 150);

  servo_move(90, 90, 90, 36, 110, 75);

  servo_move(90, 130, 140, 132, 44, 16);

  servo_move(90, 90, 90, 36, 110, 75);

  while(1){

    f = 20;

    SERVO_SPEED = 20;

    servo_move(120, 90, 90, 70, 10, 150);

    servo_move(90, 90, 90, 70, 10, 150);

  };

  */

  //实现了定点多角度抓取、放置的动作

  digitalWrite(5, HIGH);

  digitalWrite(6, LOW);

  digitalWrite(9, HIGH);

  digitalWrite(10, LOW);

  delay(1000);

  digitalWrite(5, LOW);

  digitalWrite(6, LOW);

  digitalWrite(9, LOW);

  digitalWrite(10, LOW);

  delay(1000);

  servo_move(125, 70, 70, 30, 60, 120);

  delay(500);

  servo_move(98, 70, 70, 30, 60, 120);

  delay(500);

  servo_move(98, 160, 160, 30, 60, 120);

  delay(500);

  digitalWrite(5, LOW);

  digitalWrite(6, HIGH);

  digitalWrite(9, LOW);

  digitalWrite(10, HIGH);

  delay(1000);

  digitalWrite(5, LOW);

  digitalWrite(6, LOW);

  digitalWrite(9, LOW);

  digitalWrite(10, LOW);

  delay(1000);

  servo_move(125, 160, 160, 30, 60, 120);

  delay(500);

  while(true);

}

void ServoStart(int which)

{

  if(!myServo[which].attached())myServo[which].attach(servo_port[which]);

  pinMode(servo_port[which], OUTPUT);

}

void ServoStop(int which)

{

  myServo[which].detach();

  digitalWrite(servo_port[which],LOW);

}

void ServoGo(int which , int where)

{

  if(where!=200)

  {

    if(where==201) ServoStop(which);

    else

    {

      ServoStart(which);

      myServo[which].write(where);

    }

  }

}

void servo_move(float value0, float value1, float value2, float value3, float value4, float value5)

{

  float value_arguments[] = {value0, value1, value2, value3, value4, value5};

  float value_delta[servo_num];

  for(int i=0;i<servo_num;i++)

  {

    value_delta[i] = (value_arguments[i] - value_init[i]) / f;

    /**************************串口查看输出*****************************/

//    Serial.print(value_init[i]);

//    Serial.print(" ");

//    Serial.print(value_arguments[i]);

//    Serial.print(" ");

//    Serial.println(value_delta[i]);

    /**************************串口查看输出*****************************/

  }

  for(int i=0;i<f;i++)

  {

    for(int k=0;k<servo_num;k++)

    {

      value_init[k] = value_delta[k] == 0 ? value_arguments[k] : value_init[k] + value_delta[k];

      /**************************串口查看输出*****************************/

//      Serial.print(value_init[k]);

//      Serial.print(" ");

    }

//    Serial.println();

      /**************************串口查看输出*****************************/

   

    for(int j=0;j<servo_num;j++)

    {

      ServoGo(j,value_init[j]);

    }

    delay(SERVO_SPEED);

  }

  delay(ACTION_DELAY);

  /**************************串口查看输出*****************************/

//   for(int i=0;i<6;i++)

//   {

//    Serial.println(value_init[i]);

//   }

  /**************************串口查看输出*****************************/

}

4. 扩展样机

       可以通过更换底盘、增加机械臂数量、改变机械臂安装位置、增加或减少机械臂的关节数量来对样机进行扩展。

5. 资料下载

资料内容:例程源代码、样机3D文件(含扩展及近似样机)

详情请参考: 履带式机械臂小车

### 在 ROS 中创建和控制履带式小车 #### 1. 履带式小车的建模 为了在 ROS 中实现履带式小车的建模,可以采用 URDF (Unified Robot Description Format) 或者 SDF (Simulation Description Format),这些格式用于描述机器人的物理特性和几何形状。 - **URDF 建模** 参考 ROS2 的 URDF 实现方法[^3],可以通过定义 `<link>` 和 `<joint>` 来构建履带式小车的模型。履带通常由多个链节组成,因此需要模拟链条的效果。这可能涉及复杂的关节设置以及视觉和碰撞属性的定义。 下面是一个简单的 URDF 片段示例: ```xml <?xml version="1.0"?> <robot name="tracked_vehicle"> <!-- 主体 --> <link name="base_link"> <visual> <geometry> <box size="0.5 0.3 0.2"/> </geometry> </visual> </link> <!-- 左侧履带 --> <link name="left_track_segment_1"> <visual> <geometry> <box size="0.1 0.05 0.05"/> </geometry> </visual> </link> <joint name="base_to_left_track_1" type="continuous"> <parent link="base_link"/> <child link="left_track_segment_1"/> <axis xyz="0 0 1"/> </joint> <!-- 更多链节... --> </robot> ``` 上述代码片段展示了如何通过链接 (`<link>`) 和关节 (`<joint>`) 定义履带的一部分。完整的履带需要更多的链节并正确连接它们。 --- #### 2. 控制算法的设计 对于履带式小车的控制,主要依赖于其驱动方式的选择。常见的两种模式是滑移转向(Skid Steer)[^2] 和独立电机控制。 - **滑移转向控制** 滑移转向是一种差动驱动形式,其中左侧和右侧履带分别由单独的电机驱动。速度命令可以通过 `Twist` 类型的消息传递给控制器。假设线速度为 \(v\),角速度为 \(\omega\),则两侧的速度计算如下: \[ v_{\text{left}} = v - r\cdot\omega, \quad v_{\text{right}} = v + r\cdot\omega \] 其中 \(r\) 表示两侧行驶轴的距离的一半。此公式可以直接应用于 ROS 的节点中。 - **ROS 节点实现** 下面是一个 Python 编写的简单 ROS 节点示例,该节点订阅 `/cmd_vel` 并发布左右轮的速度到两个话题上: ```python import rospy from geometry_msgs.msg import Twist from std_msgs.msg import Float64 class SkidSteerController: def __init__(self): self.left_pub = rospy.Publisher('/left_wheel_speed', Float64, queue_size=10) self.right_pub = rospy.Publisher('/right_wheel_speed', Float64, queue_size=10) rospy.Subscriber("/cmd_vel", Twist, self.cmd_callback) self.wheel_base = 0.5 # 单位:米 def cmd_callback(self, msg): linear_x = msg.linear.x angular_z = msg.angular.z vl = linear_x - (angular_z * self.wheel_base / 2) vr = linear_x + (angular_z * self.wheel_base / 2) self.left_pub.publish(Float64(vl)) self.right_pub.publish(Float64(vr)) if __name__ == '__main__': rospy.init_node('skid_steer_controller') controller = SkidSteerController() rospy.spin() ``` 以上代码实现了从 `/cmd_vel` 订阅消息并将速度转换为左右轮的速度输出的功能。 --- #### 3. Gazebo 仿真环境中的应用 如果希望测试建模和控制效果,可以在 Gazebo 中加载 URDF 文件并运行仿真。Gazebo 提供了强大的物理引擎支持复杂机械结构的动力学行为。 - 配置插件以接收速度指令。例如,在 URDF 文件中加入以下内容以便使用 `gazebo_ros_control` 插件: ```xml <gazebo> <plugin filename="libgazebo_ros_diff_drive.so" name="gazebo_ros_diff_drive_plugin"> <leftJoint>left_joint_name</leftJoint> <rightJoint>right_joint_name</rightJoint> <wheelSeparation>${wheel_separation}</wheelSeparation> <wheelDiameter>${wheel_diameter}</wheelDiameter> <commandTopic>/cmd_vel</commandTopic> <odometryTopic>/odom</odometryTopic> </plugin> </gazebo> ``` 这样就可以让 Gazebo 接收来自 ROS 的速度指令,并反馈位置信息。 --- #### 4. 边学习边实践的过程 正如提到的内容所示[^1],从零开始制作一个基于 ROS 的履带式小车是一项综合性工程,涵盖了机械设计、电气布线以及软件编程等多个领域。建议按照模块化的方式逐步推进项目进展。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值