All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Maxin B. John" <maxin.john@gmail.com>
To: gregkh@linuxfoundation.org, devel@linuxdriverproject.org
Cc: linux-kernel@vger.kernel.org
Subject: [PATCH] Support for OWI/Maplin USB Robotic Arm
Date: Mon, 8 Oct 2012 17:29:43 -0400	[thread overview]
Message-ID: <20121008212943.GA3986@linux-3ix0.site> (raw)

Hi Greg,

This driver helps us to control the OWI/Maplin USB Robotic Arm device.

I have tested this driver in my x86 Laptop and it works as expected
(Some clean-ups and modifications are in the pipeline, though).

After review process and the life in staging,I hope this driver will
find it's place in "drivers/usb/misc/" :)

The userspace utility program is available from the below URL:
https://github.com/maxinbjohn/robotic_arm_driver

OWI/Maplin USB Robotic arm is available from:
http://www.maplin.co.uk/robotic-arm-kit-with-usb-pc-interface-266257
http://www.owirobots.com/cart/html/owi-535pc-robotic-arm-kit-with-usb-pc-interface-assembled.html

Please let me know your comments.

Signed-off-by: Maxin B. John <maxin.john@gmail.com>
---
diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig
index d805eef..a1eefa9 100644
--- a/drivers/staging/Kconfig
+++ b/drivers/staging/Kconfig
@@ -144,4 +144,6 @@ source "drivers/staging/imx-drm/Kconfig"
 
 source "drivers/staging/dgrp/Kconfig"
 
+source "drivers/staging/usb_robotic_arm/Kconfig"
+
 endif # STAGING
diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
index 76e2ebd..fd9b5f3 100644
--- a/drivers/staging/Makefile
+++ b/drivers/staging/Makefile
@@ -64,3 +64,4 @@ obj-$(CONFIG_NET_VENDOR_SILICOM)	+= silicom/
 obj-$(CONFIG_CED1401)		+= ced1401/
 obj-$(CONFIG_DRM_IMX)		+= imx-drm/
 obj-$(CONFIG_DGRP)		+= dgrp/
+obj-$(CONFIG_USB_ROBOTIC_ARM)	+= usb_robotic_arm/
diff --git a/drivers/staging/usb_robotic_arm/Kconfig b/drivers/staging/usb_robotic_arm/Kconfig
new file mode 100644
index 0000000..7ac4547
--- /dev/null
+++ b/drivers/staging/usb_robotic_arm/Kconfig
@@ -0,0 +1,15 @@
+config USB_ROBOTIC_ARM
+	tristate "OWI/MAPLIN USB Robotic Arm support"
+	depends on USB
+	default N
+	---help---
+	  This enables us to control the OWI/Maplin Robotic Arm
+	  device attached to the USB port.
+
+	  For more details, and to get the userspace utility
+	  programs, please see https://github.com/maxinbjohn/robotic_arm_driver
+
+	  To compile this as a module, choose M here: the module will
+	  be called robotic_arm.
+
+	  If unsure, say N.
diff --git a/drivers/staging/usb_robotic_arm/Makefile b/drivers/staging/usb_robotic_arm/Makefile
new file mode 100644
index 0000000..9509413
--- /dev/null
+++ b/drivers/staging/usb_robotic_arm/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_USB_ROBOTIC_ARM)             += robotic_arm.o
diff --git a/drivers/staging/usb_robotic_arm/README b/drivers/staging/usb_robotic_arm/README
new file mode 100644
index 0000000..f7998ef
--- /dev/null
+++ b/drivers/staging/usb_robotic_arm/README
@@ -0,0 +1,59 @@
+
+The USB_ROBOTIC_ARM is a proof-of-concept driver for the OWI/Maplin USB
+Robotic Arm. I created it for fun. So, don't expect much from it.
+
+INSTALLATION:
+
+Select the 'USB ROBOTIC ARM' and build the kernel.
+
+If we build it as module, locate the robotic_arm.ko
+
+As 'root', insert the module:
+# insmod robotic_arm.ko
+# dmesg
+[ 8808.461441] usbcore: registered new interface driver robotic_arm
+
+Connect the Robotic Arm to the PC.
+
+# dmesg
+...
+[ 8718.729311] robotic_arm 5-1:1.0: USB ROBOTIC ARM now attached
+
+# cd /sys/bus/usb/drivers/robotic_arm/
+In my case,
+# ls
+5-1:1.0  bind  module  new_id  remove_id  uevent  unbind
+
+# cd 5-1:1.0
+# ls
+bAlternateSetting  bInterfaceNumber    bNumEndpoints  gripmotor  motor2  power                 uevent
+basemotor          bInterfaceProtocol  driver         led        motor3  subsystem
+bInterfaceClass    bInterfaceSubClass  ep_81          modalias   motor4  supports_autosuspend
+
+TESTING:
+
+# echo 1 > basemotor
+(This will rotate the base clockwise)
+
+# echo 2 > basemotor
+(This will rotate the base anti-clockwise)
+
+# echo 0 > basemotor
+(This will stop the base motor if it is on)
+
+# echo 1 > led
+(This will switch on the front side LED)
+
+# echo 1 > motor3
+(This will switch on motor3)
+
+HARDWARE AVAILABILITY:
+
+OWI/Maplin USB Robotic arm is available from:
+http://www.maplin.co.uk/robotic-arm-kit-with-usb-pc-interface-266257
+http://www.owirobots.com/cart/html/owi-535pc-robotic-arm-kit-with-usb-pc-interface-assembled.html
+
+REFERENCES:
+
+Reverse Engineering details of Robotic Arm's Protocol is available here:
+http://notbrainsurgery.livejournal.com/38622.html
diff --git a/drivers/staging/usb_robotic_arm/TODO b/drivers/staging/usb_robotic_arm/TODO
new file mode 100644
index 0000000..6c0fd7e
--- /dev/null
+++ b/drivers/staging/usb_robotic_arm/TODO
@@ -0,0 +1,8 @@
+TODO:
+	- provide independent control for motors in the hand
+	- various code clean-ups
+	- test on various platforms
+	- send to lkml for review
+
+Please send patches to Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+and Cc: Maxin B. John <maxin.john@gmail.com>
diff --git a/drivers/staging/usb_robotic_arm/robotic_arm.c b/drivers/staging/usb_robotic_arm/robotic_arm.c
new file mode 100644
index 0000000..dbde911
--- /dev/null
+++ b/drivers/staging/usb_robotic_arm/robotic_arm.c
@@ -0,0 +1,278 @@
+/*
+ * USB ROBOTIC ARM driver
+ * robotic_arm - driver for Robotic ARM with USB interface
+ * from Maplin Electronics.This is an experimental driver.
+ * Use at your own risk.
+ *
+ * Copyright (C) 2012 Maxin B. John (maxin.john@gmail.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2.
+ *
+ * Derived from USB LED driver
+ * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com)
+ */
+
+#define DEBUG 1
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+
+/* Version Information */
+#define DRIVER_VERSION "v0.1"
+#define DRIVER_AUTHOR "Maxin B. John, maxin.john@gmail.com"
+#define DRIVER_DESC "USB ROBOTIC ARM Driver"
+
+#define VENDOR_ID       0x1267
+#define PRODUCT_ID      0x0000
+
+/* table of devices that work with this driver */
+static struct usb_device_id id_table[] = {
+	{.idVendor = 0x1267, .match_flags = USB_DEVICE_ID_MATCH_VENDOR,},
+	{},
+};
+
+MODULE_DEVICE_TABLE(usb, id_table);
+
+struct usb_robotic_arm {
+	struct usb_device *udev;
+	unsigned char led;
+	unsigned char gripmotor;
+	unsigned char motor2;
+	unsigned char motor3;
+	unsigned char motor4;
+	unsigned char basemotor;
+};
+
+static void update_robotic_arm(struct usb_robotic_arm *robotic_arm)
+{
+	int retval = 0;
+	u8 cmd[3];
+
+	cmd[0] = 0;
+	cmd[1] = 0;
+	cmd[2] = 0;
+
+	/*
+	 * Byte 2 controls LED light inside the grip.
+	 * If Bit 0 is 1, LED on, otherwise LED off
+	 *
+	 */
+
+	if (robotic_arm->led)
+		cmd[2] = 1;
+
+	/*
+	 * Byte 1 controls the Base Motor
+	 * If value is 1, Base Motor rotates clockwise
+	 * If value is 2, Base Motor rotates anti-clockwise
+	 * Otherwise, Base Motor is off
+	 *
+	 */
+
+	if (robotic_arm->basemotor == 1)
+		cmd[1] = 1;
+
+	else if (robotic_arm->basemotor == 2)
+		cmd[1] = 2;
+	else
+		cmd[1] = 0;
+
+	/*
+	 * Byte 0 controls the Grip
+	 * If value is 1, Grip tightens
+	 * If values is 2, Grip Looses
+	 *
+	 */
+
+	if (robotic_arm->gripmotor == 1)
+		cmd[0] = 1;
+	else if (robotic_arm->gripmotor == 2)
+		cmd[0] = 2;
+	/*
+	 * Byte 0 controls the Motor 2
+	 * If value is 1, Motor 2 (wrist) moves up
+	 * If value is 2, Motor 2 (wrist) moves down
+	 *
+	 */
+
+	else if (robotic_arm->motor2 == 1)
+		cmd[0] = 4;
+	else if (robotic_arm->motor2 == 2)
+		cmd[0] = 8;
+
+	/*
+	 * Byte 0 controls the Motor 3
+	 * If value is 1, Motor 3 (elbow) moves up
+	 * If value is 2, Motor 3 (elbow) moves down
+	 *
+	 */
+
+	else if (robotic_arm->motor3 == 1)
+		cmd[0] = 16;
+	else if (robotic_arm->motor3 == 2)
+		cmd[0] = 32;
+
+	/*
+	 * Byte 0 controls the Motor 4
+	 * If value is 1, Motor 4 (shoulder) moves up
+	 * If value is 2, Motor 4 (shoulder) moves down
+	 *
+	 */
+
+	else if (robotic_arm->motor4 == 1)
+		cmd[0] = 64;
+	else if (robotic_arm->motor4 == 2)
+		cmd[0] = 128;
+	else
+		cmd[0] = 0;
+
+	retval = usb_control_msg(robotic_arm->udev,
+				 usb_sndctrlpipe(robotic_arm->udev, 0),
+				 6, 0x40, 0x100, 0, cmd, 3, 0);
+
+
+	if (retval)
+		dev_dbg(&robotic_arm->udev->dev, "retval = %d\n", retval);
+
+}
+
+#define show_set(value) \
+static ssize_t show_##value(struct device *dev, struct device_attribute *attr,\
+			char *buf)					\
+{									\
+	struct usb_interface *intf = to_usb_interface(dev);		\
+	struct usb_robotic_arm *robotic_arm = usb_get_intfdata(intf);	\
+									\
+	return sprintf(buf, "%d\n", robotic_arm->value);		\
+}                                                                       \
+static ssize_t set_##value(struct device *dev, struct device_attribute *attr,\
+				const char *buf, size_t count)		\
+{                                                                       \
+	struct usb_interface *intf = to_usb_interface(dev);             \
+	struct usb_robotic_arm *robotic_arm = usb_get_intfdata(intf);   \
+	int ret = -ENXIO;						\
+	unsigned long val;						\
+									\
+	ret = kstrtoul(buf, 0, &val);					\
+	if (ret)							\
+		return ret;						\
+	robotic_arm->value = val;					\
+	update_robotic_arm(robotic_arm);                                \
+	return count;                                                   \
+}                                                                       \
+static DEVICE_ATTR(value, S_IRUGO | S_IWUSR, show_##value, set_##value);
+show_set(led);
+show_set(gripmotor);
+show_set(motor2);
+show_set(motor3);
+show_set(motor4);
+show_set(basemotor);
+
+static int robotic_arm_probe(struct usb_interface *interface,
+			     const struct usb_device_id *id)
+{
+	struct usb_device *udev;
+	struct usb_robotic_arm *dev;
+	int retval = -ENOMEM;
+
+	udev = interface_to_usbdev(interface);
+	dev = kzalloc(sizeof(struct usb_robotic_arm), GFP_KERNEL);
+	if (dev == NULL) {
+		dev_err(&interface->dev, "out of memory\n");
+		goto error_mem;
+	}
+
+	dev->udev = usb_get_dev(udev);
+
+	usb_set_intfdata(interface, dev);
+
+	retval = device_create_file(&interface->dev, &dev_attr_led);
+	if (retval)
+		goto error;
+	retval = device_create_file(&interface->dev, &dev_attr_gripmotor);
+	if (retval)
+		goto error;
+	retval = device_create_file(&interface->dev, &dev_attr_motor2);
+	if (retval)
+		goto error;
+	retval = device_create_file(&interface->dev, &dev_attr_motor3);
+	if (retval)
+		goto error;
+	retval = device_create_file(&interface->dev, &dev_attr_motor4);
+	if (retval)
+		goto error;
+	retval = device_create_file(&interface->dev, &dev_attr_basemotor);
+	if (retval)
+		goto error;
+
+	dev_info(&interface->dev, "USB ROBOTIC ARM now attached\n");
+	return 0;
+
+error:
+	device_remove_file(&interface->dev, &dev_attr_led);
+	device_remove_file(&interface->dev, &dev_attr_gripmotor);
+	device_remove_file(&interface->dev, &dev_attr_motor2);
+	device_remove_file(&interface->dev, &dev_attr_motor3);
+	device_remove_file(&interface->dev, &dev_attr_motor4);
+	device_remove_file(&interface->dev, &dev_attr_basemotor);
+
+	usb_set_intfdata(interface, NULL);
+	usb_put_dev(dev->udev);
+	kfree(dev);
+
+error_mem:
+	return retval;
+}
+
+static void robotic_arm_disconnect(struct usb_interface *interface)
+{
+	struct usb_robotic_arm *dev = NULL;
+
+	dev = usb_get_intfdata(interface);
+
+	device_remove_file(&interface->dev, &dev_attr_led);
+	device_remove_file(&interface->dev, &dev_attr_gripmotor);
+	device_remove_file(&interface->dev, &dev_attr_motor2);
+	device_remove_file(&interface->dev, &dev_attr_motor3);
+	device_remove_file(&interface->dev, &dev_attr_motor4);
+	device_remove_file(&interface->dev, &dev_attr_basemotor);
+
+	/* first remove the files, then set the pointer to NULL */
+	usb_set_intfdata(interface, NULL);
+
+	usb_put_dev(dev->udev);
+
+	kfree(dev);
+
+	dev_info(&interface->dev, "USB ROBOTIC ARM now disconnected\n");
+}
+
+static struct usb_driver robotic_arm_driver = {
+	.name = "robotic_arm",
+	.probe = robotic_arm_probe,
+	.disconnect = robotic_arm_disconnect,
+	.id_table = id_table,
+};
+
+static int __init usb_robotic_arm_init(void)
+{
+	return usb_register(&robotic_arm_driver);
+}
+
+static void __exit usb_robotic_arm_exit(void)
+{
+	usb_deregister(&robotic_arm_driver);
+}
+
+module_init(usb_robotic_arm_init);
+module_exit(usb_robotic_arm_exit);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");

             reply	other threads:[~2012-10-08 21:26 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-10-08 21:29 Maxin B. John [this message]
2012-10-08 23:55 ` [PATCH] Support for OWI/Maplin USB Robotic Arm Greg KH
2012-10-09  3:52   ` Maxin B John
2012-10-22 22:40     ` Greg KH

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20121008212943.GA3986@linux-3ix0.site \
    --to=maxin.john@gmail.com \
    --cc=devel@linuxdriverproject.org \
    --cc=gregkh@linuxfoundation.org \
    --cc=linux-kernel@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.